summaryrefslogtreecommitdiff
path: root/src/mmo
diff options
context:
space:
mode:
Diffstat (limited to 'src/mmo')
-rw-r--r--src/mmo/config_parse.cpp24
-rw-r--r--src/mmo/config_parse.hpp13
-rw-r--r--src/mmo/consts.cpp26
-rw-r--r--src/mmo/consts.hpp66
-rw-r--r--src/mmo/core.cpp54
-rw-r--r--src/mmo/core.hpp15
-rw-r--r--src/mmo/dumb_ptr.hpp274
-rw-r--r--src/mmo/enums.cpp26
-rw-r--r--src/mmo/enums.hpp162
-rw-r--r--src/mmo/extract.cpp48
-rw-r--r--src/mmo/extract.hpp68
-rw-r--r--src/mmo/extract_test.cpp384
-rw-r--r--src/mmo/fwd.hpp68
-rw-r--r--src/mmo/human_time_diff.cpp5
-rw-r--r--src/mmo/human_time_diff.hpp31
-rw-r--r--src/mmo/human_time_diff_test.cpp38
-rw-r--r--src/mmo/ids.cpp26
-rw-r--r--src/mmo/ids.hpp168
-rw-r--r--src/mmo/ip.cpp114
-rw-r--r--src/mmo/ip.hpp164
-rw-r--r--src/mmo/ip.py14
-rw-r--r--src/mmo/ip_test.cpp352
-rw-r--r--src/mmo/md5more.cpp15
-rw-r--r--src/mmo/md5more.hpp18
-rw-r--r--src/mmo/mmo.cpp5
-rw-r--r--src/mmo/mmo.hpp380
-rw-r--r--src/mmo/socket.cpp508
-rw-r--r--src/mmo/socket.hpp424
-rw-r--r--src/mmo/strs.cpp (renamed from src/mmo/dumb_ptr.cpp)11
-rw-r--r--src/mmo/strs.hpp126
-rw-r--r--src/mmo/timer.cpp221
-rw-r--r--src/mmo/timer.hpp50
-rw-r--r--src/mmo/timer.t.hpp90
-rw-r--r--src/mmo/utils.cpp28
-rw-r--r--src/mmo/utils.hpp68
-rw-r--r--src/mmo/version.cpp6
-rw-r--r--src/mmo/version.hpp86
37 files changed, 1221 insertions, 2955 deletions
diff --git a/src/mmo/config_parse.cpp b/src/mmo/config_parse.cpp
index b954e8b..8362810 100644
--- a/src/mmo/config_parse.cpp
+++ b/src/mmo/config_parse.cpp
@@ -18,6 +18,8 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+#include <algorithm>
+
#include "../strings/xstring.hpp"
#include "../strings/zstring.hpp"
@@ -28,9 +30,12 @@
#include "../poison.hpp"
+
+namespace tmwa
+{
bool is_comment(XString line)
{
- return not line or line.startswith("//");
+ return not line or line.startswith("//"_s);
}
template<class ZS>
@@ -72,7 +77,7 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
io::LineReader in(filename);
if (!in.is_open())
{
- PRINTF("Unable to open file: %s\n", filename);
+ PRINTF("Unable to open file: %s\n"_fmt, filename);
return false;
}
io::Line line;
@@ -85,16 +90,16 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
ZString value;
if (!config_split(line.text, &key, &value))
{
- line.error("Bad config line");
+ line.error("Bad config line"_s);
rv = false;
continue;
}
- if (key == "import")
+ if (key == "import"_s)
{
rv &= load_config_file(value, slave);
continue;
}
- else if (key == "version-lt")
+ else if (key == "version-lt"_s)
{
Version vers;
if (!extract(value, &vers))
@@ -106,7 +111,7 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
continue;
break;
}
- else if (key == "version-le")
+ else if (key == "version-le"_s)
{
Version vers;
if (!extract(value, &vers))
@@ -118,7 +123,7 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
continue;
break;
}
- else if (key == "version-gt")
+ else if (key == "version-gt"_s)
{
Version vers;
if (!extract(value, &vers))
@@ -130,7 +135,7 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
continue;
break;
}
- else if (key == "version-ge")
+ else if (key == "version-ge"_s)
{
Version vers;
if (!extract(value, &vers))
@@ -144,7 +149,7 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
}
else if (!slave(key, value))
{
- line.error("Bad config key or value");
+ line.error("Bad config key or value"_s);
rv = false;
continue;
}
@@ -152,3 +157,4 @@ bool load_config_file(ZString filename, ConfigItemParser slave)
}
return rv;
}
+} // namespace tmwa
diff --git a/src/mmo/config_parse.hpp b/src/mmo/config_parse.hpp
index dd1b79e..50a115e 100644
--- a/src/mmo/config_parse.hpp
+++ b/src/mmo/config_parse.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_CONFIG_PARSE_HPP
-#define TMWA_MMO_CONFIG_PARSE_HPP
+#pragma once
// config_parse.hpp - Framework for per-server config parsers.
//
// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
@@ -19,10 +18,13 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
+
+namespace tmwa
+{
typedef bool (*ConfigItemParser)(XString key, ZString value);
bool is_comment(XString line);
@@ -32,5 +34,4 @@ bool config_split(XString line, XString *key, XString *value);
/// Master config parser. This handles 'import' and 'version-ge' etc.
/// Then it defers to the inferior parser for a line it does not understand.
bool load_config_file(ZString filename, ConfigItemParser slave);
-
-#endif // TMWA_MMO_CONFIG_PARSE_HPP
+} // namespace tmwa
diff --git a/src/mmo/consts.cpp b/src/mmo/consts.cpp
new file mode 100644
index 0000000..e49cdf5
--- /dev/null
+++ b/src/mmo/consts.cpp
@@ -0,0 +1,26 @@
+#include "consts.hpp"
+// consts.cpp - empty mess of constants
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa
diff --git a/src/mmo/consts.hpp b/src/mmo/consts.hpp
new file mode 100644
index 0000000..c1a7eb6
--- /dev/null
+++ b/src/mmo/consts.hpp
@@ -0,0 +1,66 @@
+#pragma once
+// consts.hpp - Huge mess of constants.
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../net/timer.t.hpp"
+
+#include "ids.hpp"
+#include "strs.hpp"
+
+
+namespace tmwa
+{
+constexpr int FIFOSIZE_SERVERLINK = 256 * 1024;
+
+constexpr int MAX_MAP_PER_SERVER = 512;
+constexpr int MAX_INVENTORY = 100;
+constexpr int MAX_AMOUNT = 30000;
+constexpr int MAX_ZENY = 1000000000; // 1G zeny
+constexpr int TRADE_MAX = 10;
+
+constexpr int GLOBAL_REG_NUM = 96;
+constexpr size_t ACCOUNT_REG_NUM = 16;
+constexpr size_t ACCOUNT_REG2_NUM = 16;
+constexpr interval_t DEFAULT_WALK_SPEED = 150_ms;
+constexpr interval_t MIN_WALK_SPEED = interval_t::zero();
+constexpr interval_t MAX_WALK_SPEED = 1_s;
+constexpr int MAX_STORAGE = 300;
+constexpr int MAX_PARTY = 12;
+
+#define MIN_HAIR_STYLE battle_config.min_hair_style
+#define MAX_HAIR_STYLE battle_config.max_hair_style
+#define MIN_HAIR_COLOR battle_config.min_hair_color
+#define MAX_HAIR_COLOR battle_config.max_hair_color
+#define MIN_CLOTH_COLOR battle_config.min_cloth_color
+#define MAX_CLOTH_COLOR battle_config.max_cloth_color
+
+// WTF is this doing here?
+struct PartyMember
+{
+ AccountId account_id;
+ CharName name;
+ MapName map;
+ int leader, online, lv;
+ struct map_session_data *sd;
+};
+} // namespace tmwa
diff --git a/src/mmo/core.cpp b/src/mmo/core.cpp
index 68b7823..f1a8d07 100644
--- a/src/mmo/core.cpp
+++ b/src/mmo/core.cpp
@@ -22,23 +22,26 @@
#include <sys/wait.h>
-#include <unistd.h>
+#include <alloca.h>
#include <csignal>
#include <cstdlib>
-#include <ctime>
-#include "../strings/zstring.hpp"
+#include <tmwa/shared.hpp>
-#include "../generic/random.hpp"
+#include "../strings/zstring.hpp"
+#include "../strings/literal.hpp"
#include "../io/cxxstdio.hpp"
-#include "socket.hpp"
-#include "timer.hpp"
+#include "../net/socket.hpp"
+#include "../net/timer.hpp"
#include "../poison.hpp"
+
+namespace tmwa
+{
// Added by Gabuzomeu
//
// This is an implementation of signal() using sigaction() for portability.
@@ -61,10 +64,12 @@ sigfunc compat_signal(int signo, sigfunc func)
sact.sa_flags = 0;
if (sigaction(signo, &sact, &oact) < 0)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
+ {
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
return SIG_ERR;
-#pragma GCC diagnostic pop
+ DIAG_POP();
+ }
return oact.sa_handler;
}
@@ -75,16 +80,18 @@ bool runflag = true;
static
void chld_proc(int)
{
- wait(NULL);
+ wait(nullptr);
}
static
void sig_proc(int)
{
for (int i = 1; i < 31; ++i)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
+ {
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
compat_signal(i, SIG_IGN);
-#pragma GCC diagnostic pop
+ DIAG_POP();
+ }
runflag = false;
}
@@ -97,8 +104,14 @@ void sig_proc(int)
Unless you use SA_SIGINFO and *carefully* check the origin,
that means they must be SIG_DFL.
*/
+} // namespace tmwa
+
int main(int argc, char **argv)
{
+ using namespace tmwa;
+
+ check_paths();
+
// ZString args[argc]; is (deliberately!) not supported by clang yet
ZString *args = static_cast<ZString *>(alloca(argc * sizeof(ZString)));
for (int i = 0; i < argc; ++i)
@@ -107,29 +120,30 @@ int main(int argc, char **argv)
if (!runflag)
{
- PRINTF("Fatal error during startup; exiting\n");
+ PRINTF("Fatal error during startup; exiting\n"_fmt);
return 1;
}
// set up exit handlers *after* the initialization has happened.
// This is because term_func is likely to depend on successful init.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
compat_signal(SIGPIPE, SIG_IGN);
-#pragma GCC diagnostic pop
+ DIAG_POP();
compat_signal(SIGTERM, sig_proc);
compat_signal(SIGINT, sig_proc);
compat_signal(SIGCHLD, chld_proc);
// Signal to create coredumps by system when necessary (crash)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
+ DIAG_PUSH();
+ DIAG_I(old_style_cast);
+ DIAG_I(zero_as_null_pointer_constant);
compat_signal(SIGSEGV, SIG_DFL);
compat_signal(SIGBUS, SIG_DFL);
compat_signal(SIGTRAP, SIG_DFL);
compat_signal(SIGILL, SIG_DFL);
compat_signal(SIGFPE, SIG_DFL);
-#pragma GCC diagnostic pop
+ DIAG_POP();
atexit(term_func);
diff --git a/src/mmo/core.hpp b/src/mmo/core.hpp
index 5699045..5b2dbbb 100644
--- a/src/mmo/core.hpp
+++ b/src/mmo/core.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_CORE_HPP
-#define TMWA_MMO_CORE_HPP
+#pragma once
// core.hpp - The main loop.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,12 +20,15 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../range/slice.hpp"
+#include "../range/slice.hpp"
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
+
+namespace tmwa
+{
/// core.c contains a server-independent main() function
/// and then runs a do_sendrecv loop
@@ -40,5 +42,4 @@ extern int do_init(Slice<ZString>);
/// Cleanup function called whenever a signal kills us
/// or when if we manage to exit() gracefully.
extern void term_func(void);
-
-#endif // TMWA_MMO_CORE_HPP
+} // namespace tmwa
diff --git a/src/mmo/dumb_ptr.hpp b/src/mmo/dumb_ptr.hpp
deleted file mode 100644
index 9632945..0000000
--- a/src/mmo/dumb_ptr.hpp
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifndef TMWA_MMO_DUMB_PTR_HPP
-#define TMWA_MMO_DUMB_PTR_HPP
-// ptr.hpp - temporary new/delete wrappers
-//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# include "../sanity.hpp"
-
-# include <cstring>
-
-# include <algorithm>
-
-# include "../strings/astring.hpp"
-# include "../strings/zstring.hpp"
-# include "../strings/xstring.hpp"
-
-// unmanaged new/delete-able pointer
-// should be replaced by std::unique_ptr<T>
-template<class T>
-class dumb_ptr
-{
- template<class U>
- friend class dumb_ptr;
- T *impl;
-public:
- explicit
- dumb_ptr(T *p=nullptr)
- : impl(p)
- {}
- template<class U>
- dumb_ptr(dumb_ptr<U> p)
- : impl(p.impl)
- {}
- dumb_ptr(std::nullptr_t)
- : impl(nullptr)
- {}
-
- void delete_()
- {
- delete impl;
- *this = nullptr;
- }
- template<class... A>
- void new_(A&&... a)
- {
- impl = new T(std::forward<A>(a)...);
- }
- template<class... A>
- static
- dumb_ptr<T> make(A&&... a)
- {
- return dumb_ptr<T>(new T(std::forward<A>(a)...));
- }
- dumb_ptr& operator = (std::nullptr_t)
- {
- impl = nullptr;
- return *this;
- }
-
- T& operator *() const
- {
- return *impl;
- }
- T *operator->() const
- {
- return impl;
- }
-
- explicit
- operator bool() const
- {
- return impl;
- }
- bool operator !() const
- {
- return !impl;
- }
-
- friend bool operator == (dumb_ptr l, dumb_ptr r)
- {
- return l.impl == r.impl;
- }
- friend bool operator != (dumb_ptr l, dumb_ptr r)
- {
- return !(l == r);
- }
-};
-
-// unmanaged new/delete-able pointer
-// should be replaced by std::unique_ptr<T[]> or std::vector<T>
-template<class T>
-class dumb_ptr<T[]>
-{
- T *impl;
- size_t sz;
-public:
- dumb_ptr() : impl(), sz() {}
- dumb_ptr(std::nullptr_t)
- : impl(nullptr), sz(0) {}
- dumb_ptr(T *p, size_t z)
- : impl(p)
- , sz(z)
- {}
-
- void delete_()
- {
- delete[] impl;
- *this = nullptr;
- }
- void new_(size_t z)
- {
- impl = new T[z]();
- sz = z;
- }
- static
- dumb_ptr<T[]> make(size_t z)
- {
- return dumb_ptr<T[]>(new T[z](), z);
- }
- dumb_ptr& operator = (std::nullptr_t)
- {
- impl = nullptr;
- sz = 0;
- return *this;
- }
-
- size_t size() const
- {
- return sz;
- }
- void resize(size_t z)
- {
- if (z == sz)
- return;
- T *np = new T[z]();
- // not exception-safe, but we don't have a dtor anyway
- size_t i = std::min(z, sz);
- while (i-->0)
- np[i] = std::move(impl[i]);
- delete[] impl;
- impl = np;
- sz = z;
- }
-
- T& operator[](size_t i) const
- {
- return impl[i];
- }
-
- explicit
- operator bool() const
- {
- return impl;
- }
- bool operator !() const
- {
- return !impl;
- }
-
- friend bool operator == (dumb_ptr l, dumb_ptr r)
- {
- return l.impl == r.impl;
- }
- friend bool operator != (dumb_ptr l, dumb_ptr r)
- {
- return !(l == r);
- }
-};
-
-struct dumb_string
-{
- dumb_ptr<char[]> impl;
-
- dumb_string()
- : impl()
- {}
- dumb_string(char *) = delete;
- // copy ctor, copy assign, and dtor are all default
-
- static dumb_string copy(const char *b, const char *e)
- {
- dumb_string rv;
- rv.impl.new_((e - b) + 1);
- std::copy(b, e, &rv.impl[0]);
- return rv;
- }
- static dumb_string copy(const char *sz)
- {
- return dumb_string::copy(sz, sz + strlen(sz));
- }
- static dumb_string copys(XString s)
- {
- return dumb_string::copy(&*s.begin(), &*s.end());
- }
- static
-# ifndef __clang__
- __attribute__((warning("shouldn't use this - slice instead")))
-# endif
- dumb_string copyn(const char *sn, size_t n)
- {
- return dumb_string::copy(sn, sn + strnlen(sn, n));
- }
-
- static
- dumb_string fake(ZString p)
- {
- dumb_string rv;
- size_t len = p.size();
- rv.impl = dumb_ptr<char[]>(const_cast<char *>(p.c_str()), len);
- return rv;
- }
-
- dumb_string dup() const
- {
- return dumb_string::copy(&impl[0]);
- }
- void delete_()
- {
- impl.delete_();
- }
-
- const char *c_str() const
- {
- return &impl[0];
- }
-
- operator ZString() const
- {
- return ZString(strings::really_construct_from_a_pointer, c_str(), nullptr);
- }
-
- AString str() const
- {
- return ZString(*this);
- }
-
- char& operator[](size_t i) const
- {
- return impl[i];
- }
-
- explicit
- operator bool() const
- {
- return bool(impl);
- }
- bool operator !() const
- {
- return !impl;
- }
-};
-
-inline
-const char *convert_for_printf(dumb_string ds)
-{
- return ds.c_str();
-}
-
-#endif // TMWA_MMO_DUMB_PTR_HPP
diff --git a/src/mmo/enums.cpp b/src/mmo/enums.cpp
new file mode 100644
index 0000000..d05be91
--- /dev/null
+++ b/src/mmo/enums.cpp
@@ -0,0 +1,26 @@
+#include "enums.hpp"
+// enums.cpp - Common enumerated types
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa
diff --git a/src/mmo/enums.hpp b/src/mmo/enums.hpp
new file mode 100644
index 0000000..bf8a75c
--- /dev/null
+++ b/src/mmo/enums.hpp
@@ -0,0 +1,162 @@
+#pragma once
+// enums.hpp - Common enumerated types
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include <cstdint>
+
+#include "../generic/enum.hpp"
+
+
+namespace tmwa
+{
+enum class SkillID : uint16_t;
+constexpr SkillID MAX_SKILL = SkillID(474); // not 450
+constexpr SkillID get_enum_min_value(SkillID) { return SkillID(); }
+constexpr SkillID get_enum_max_value(SkillID) { return MAX_SKILL; }
+
+namespace e
+{
+enum class EPOS : uint16_t
+{
+ ZERO = 0x0000,
+
+ LEGS = 0x0001,
+ WEAPON = 0x0002,
+ GLOVES = 0x0004,
+ CAPE = 0x0008,
+ MISC1 = 0x0010,
+ SHIELD = 0x0020,
+ SHOES = 0x0040,
+ MISC2 = 0x0080,
+ HAT = 0x0100,
+ TORSO = 0x0200,
+
+ ARROW = 0x8000,
+};
+ENUM_BITWISE_OPERATORS(EPOS)
+
+constexpr EPOS get_enum_min_value(EPOS) { return EPOS(0x0000); }
+constexpr EPOS get_enum_max_value(EPOS) { return EPOS(0xffff); }
+}
+using e::EPOS;
+
+namespace e
+{
+enum class SkillFlags : uint16_t;
+}
+using e::SkillFlags;
+
+// Option and Opt1..3 in map.hpp
+namespace e
+{
+enum class Option : uint16_t;
+constexpr Option get_enum_min_value(Option) { return Option(0x0000); }
+constexpr Option get_enum_max_value(Option) { return Option(0xffff); }
+}
+using e::Option;
+
+enum class ATTR
+{
+ STR = 0,
+ AGI = 1,
+ VIT = 2,
+ INT = 3,
+ DEX = 4,
+ LUK = 5,
+
+ COUNT = 6,
+};
+
+constexpr ATTR ATTRs[6] =
+{
+ ATTR::STR,
+ ATTR::AGI,
+ ATTR::VIT,
+ ATTR::INT,
+ ATTR::DEX,
+ ATTR::LUK,
+};
+
+enum class ItemLook : uint16_t
+{
+ NONE = 0,
+ BLADE = 1, // or some other common weapons
+ _2,
+ SETZER_AND_SCYTHE = 3,
+ _6,
+ STAFF = 10,
+ BOW = 11,
+ _13 = 13,
+ _14 = 14,
+ _16 = 16,
+ SINGLE_HANDED_COUNT = 17,
+
+ DUAL_BLADE = 0x11,
+ DUAL_2 = 0x12,
+ DUAL_6 = 0x13,
+ DUAL_12 = 0x14,
+ DUAL_16 = 0x15,
+ DUAL_26 = 0x16,
+};
+
+enum class SEX : uint8_t
+{
+ FEMALE = 0,
+ MALE = 1,
+ // For items. This is also used as error, sometime.
+ NEUTRAL = 2,
+};
+inline
+char sex_to_char(SEX sex)
+{
+ switch (sex)
+ {
+ case SEX::FEMALE: return 'F';
+ case SEX::MALE: return 'M';
+ default: return '\0';
+ }
+}
+inline
+SEX sex_from_char(char c)
+{
+ switch (c)
+ {
+ case 'F': return SEX::FEMALE;
+ case 'M': return SEX::MALE;
+ default: return SEX::NEUTRAL;
+ }
+}
+
+inline
+bool native_to_network(char *network, SEX native)
+{
+ *network = sex_to_char(native);
+ return true;
+}
+inline
+bool network_to_native(SEX *native, char network)
+{
+ *native = sex_from_char(network);
+ return true;
+}
+} // namespace tmwa
diff --git a/src/mmo/extract.cpp b/src/mmo/extract.cpp
index 378986d..d486ed5 100644
--- a/src/mmo/extract.cpp
+++ b/src/mmo/extract.cpp
@@ -18,12 +18,19 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+#include <algorithm>
+
#include "../strings/astring.hpp"
#include "../strings/xstring.hpp"
#include "../strings/vstring.hpp"
+#include "mmo.hpp"
+
#include "../poison.hpp"
+
+namespace tmwa
+{
bool extract(XString str, XString *rv)
{
*rv = str;
@@ -36,20 +43,21 @@ bool extract(XString str, AString *rv)
return true;
}
-bool extract(XString str, struct global_reg *var)
+bool extract(XString str, GlobalReg *var)
{
return extract(str,
record<','>(&var->str, &var->value));
}
-bool extract(XString str, struct item *it)
+bool extract(XString str, Item *it)
{
XString ignored;
- return extract(str,
+ XString corruption_hack_amount;
+ bool rv = extract(str,
record<',', 11>(
- &it->id,
+ &ignored,
&it->nameid,
- &it->amount,
+ &corruption_hack_amount,
&it->equip,
&ignored,
&ignored,
@@ -59,4 +67,34 @@ bool extract(XString str, struct item *it)
&ignored,
&ignored,
&ignored));
+ if (rv)
+ {
+ if (corruption_hack_amount == "-1"_s)
+ it->amount = 0;
+ else
+ rv = extract(corruption_hack_amount, &it->amount);
+ }
+ return rv;
+}
+
+bool extract(XString str, MapName *m)
+{
+ XString::iterator it = std::find(str.begin(), str.end(), '.');
+ str = str.xislice_h(it);
+ VString<15> tmp;
+ bool rv = extract(str, &tmp);
+ *m = tmp;
+ return rv;
+}
+
+bool extract(XString str, CharName *out)
+{
+ VString<23> tmp;
+ if (extract(str, &tmp))
+ {
+ *out = CharName(tmp);
+ return true;
+ }
+ return false;
}
+} // namespace tmwa
diff --git a/src/mmo/extract.hpp b/src/mmo/extract.hpp
index 622281b..355e2da 100644
--- a/src/mmo/extract.hpp
+++ b/src/mmo/extract.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_EXTRACT_HPP
-#define TMWA_MMO_EXTRACT_HPP
+#pragma once
// extract.hpp - a simple, hierarchical, tokenizer
//
// Copyright © 2012-2013 Ben Longbons <b.r.longbons@gmail.com>
@@ -19,14 +18,27 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include <algorithm>
+#include <cerrno>
+#include <cstdlib>
-# include "../strings/xstring.hpp"
+#include <algorithm>
+#include <vector>
-# include "mmo.hpp"
-# include "utils.hpp"
+#include "../ints/wrap.hpp"
+
+#include "../strings/xstring.hpp"
+
+#include "../generic/enum.hpp"
+
+#include "utils.hpp"
+
+
+namespace tmwa
+{
+template<class T>
+bool do_extract(XString str, T t);
template<class T, typename=typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, char>::value && !std::is_same<T, bool>::value>::type>
bool extract(XString str, T *iv)
@@ -94,6 +106,12 @@ bool extract(XString str, VString<N> *out)
return true;
}
+inline
+bool extract(XString str, LString exact)
+{
+ return str == exact;
+}
+
template<class T>
class LStripper
{
@@ -192,31 +210,23 @@ bool extract(XString str, VRecord<split, T> rec)
&& extract(str.xislice_t(s + 1), rec);
}
-bool extract(XString str, struct global_reg *var);
+bool extract(XString str, GlobalReg *var);
-bool extract(XString str, struct item *it);
+bool extract(XString str, Item *it);
-inline
-bool extract(XString str, MapName *m)
-{
- XString::iterator it = std::find(str.begin(), str.end(), '.');
- str = str.xislice_h(it);
- VString<15> tmp;
- bool rv = extract(str, &tmp);
- *m = tmp;
- return rv;
-}
+bool extract(XString str, MapName *m);
-inline
-bool extract(XString str, CharName *out)
+bool extract(XString str, CharName *out);
+
+template<class T>
+bool do_extract(XString str, T t)
{
- VString<23> tmp;
- if (extract(str, &tmp))
- {
- *out = CharName(tmp);
- return true;
- }
- return false;
+ return extract(str, t);
}
-#endif // TMWA_MMO_EXTRACT_HPP
+template<class R>
+bool extract(XString str, Wrapped<R> *w)
+{
+ return extract(str, &w->_value);
+}
+} // namespace tmwa
diff --git a/src/mmo/extract_test.cpp b/src/mmo/extract_test.cpp
index 60ab49e..e6dc7b2 100644
--- a/src/mmo/extract_test.cpp
+++ b/src/mmo/extract_test.cpp
@@ -22,160 +22,165 @@
#include "../strings/xstring.hpp"
+#include "mmo.hpp"
+
#include "../poison.hpp"
+
+namespace tmwa
+{
TEST(extract, record_int)
{
int x, y, z;
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 3 4 ", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 3 4 "_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 3 4", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 3 4"_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 3 ", record<' '>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 3 "_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 3", record<' '>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 3"_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 ", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 "_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2"_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 ", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 "_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1"_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract(" ", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract(" "_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(0, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("", record<' '>(&x, &y, &z)));
+ EXPECT_FALSE(extract(""_s, record<' '>(&x, &y, &z)));
EXPECT_EQ(0, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 2>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 3 4", record<' ', 2>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 3 ", record<' ', 2>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 3", record<' ', 2>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 3"_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 ", record<' ', 2>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 "_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2", record<' ', 2>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2"_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 ", record<' ', 2>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 "_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1", record<' ', 2>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1"_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract(" ", record<' ', 2>(&x, &y, &z)));
+ EXPECT_FALSE(extract(" "_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(0, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("", record<' ', 2>(&x, &y, &z)));
+ EXPECT_FALSE(extract(""_s, record<' ', 2>(&x, &y, &z)));
EXPECT_EQ(0, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 1>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_FALSE(extract("1 2 3 4", record<' ', 1>(&x, &y, &z)));
+ EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 3 ", record<' ', 1>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 3", record<' ', 1>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 3"_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(3, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2 ", record<' ', 1>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2 "_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 2", record<' ', 1>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 2"_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(2, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1 ", record<' ', 1>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1 "_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_TRUE(extract("1", record<' ', 1>(&x, &y, &z)));
+ EXPECT_TRUE(extract("1"_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(1, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract(" ", record<' ', 1>(&x, &y, &z)));
+ EXPECT_FALSE(extract(" "_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(0, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
x = y = z = 0;
- EXPECT_FALSE(extract("", record<' ', 1>(&x, &y, &z)));
+ EXPECT_FALSE(extract(""_s, record<' ', 1>(&x, &y, &z)));
EXPECT_EQ(0, x);
EXPECT_EQ(0, y);
EXPECT_EQ(0, z);
@@ -185,170 +190,171 @@ TEST(extract, record_int)
TEST(extract, record_str)
{
XString x, y, z;
- x = y = z = "";
- EXPECT_FALSE(extract("1 2 3 4 ", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1 2 3 4", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 3 ", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 3", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 ", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1 2", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1 ", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1", record<' '>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract(" ", record<' '>(&x, &y, &z)));
- EXPECT_EQ("", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract("", record<' '>(&x, &y, &z)));
- EXPECT_EQ("", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1 2 3 4 "_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1 2 3 4"_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 3 "_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 3"_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 "_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1 2"_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1 "_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1"_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract(" "_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ(""_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract(""_s, record<' '>(&x, &y, &z)));
+ EXPECT_EQ(""_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
- EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1 2 3 4", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 3 ", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 3", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 ", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 ", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract(" ", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_FALSE(extract("", record<' ', 2>(&x, &y, &z)));
- EXPECT_EQ("", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
+ EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 3"_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 "_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2"_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 "_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1"_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract(" "_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ(""_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract(""_s, record<' ', 2>(&x, &y, &z)));
+ EXPECT_EQ(""_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
- EXPECT_FALSE(extract("1 2 3 4 ", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_FALSE(extract("1 2 3 4", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 3 ", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 3", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("3", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2 ", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 2", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("2", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1 ", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract("1", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("1", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract(" ", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
- EXPECT_TRUE(extract("", record<' ', 1>(&x, &y, &z)));
- EXPECT_EQ("", x);
- EXPECT_EQ("", y);
- EXPECT_EQ("", z);
- x = y = z = "";
+ EXPECT_FALSE(extract("1 2 3 4 "_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_FALSE(extract("1 2 3 4"_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 3 "_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 3"_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ("3"_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2 "_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 2"_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ("2"_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1 "_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract("1"_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ("1"_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract(" "_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ(""_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
+ EXPECT_TRUE(extract(""_s, record<' ', 1>(&x, &y, &z)));
+ EXPECT_EQ(""_s, x);
+ EXPECT_EQ(""_s, y);
+ EXPECT_EQ(""_s, z);
+ x = y = z = ""_s;
}
TEST(extract, mapname)
{
MapName map;
- EXPECT_TRUE(extract("abc", &map));
- EXPECT_EQ(map, "abc");
- EXPECT_TRUE(extract("abc.gat", &map));
- EXPECT_EQ(map, "abc");
- EXPECT_TRUE(extract("abcdefghijklmno", &map));
- EXPECT_EQ(map, "abcdefghijklmno");
- EXPECT_TRUE(extract("abcdefghijklmno.gat", &map));
- EXPECT_EQ(map, "abcdefghijklmno");
+ EXPECT_TRUE(extract("abc"_s, &map));
+ EXPECT_EQ(map, "abc"_s);
+ EXPECT_TRUE(extract("abc.gat"_s, &map));
+ EXPECT_EQ(map, "abc"_s);
+ EXPECT_TRUE(extract("abcdefghijklmno"_s, &map));
+ EXPECT_EQ(map, "abcdefghijklmno"_s);
+ EXPECT_TRUE(extract("abcdefghijklmno.gat"_s, &map));
+ EXPECT_EQ(map, "abcdefghijklmno"_s);
}
+} // namespace tmwa
diff --git a/src/mmo/fwd.hpp b/src/mmo/fwd.hpp
new file mode 100644
index 0000000..3b56bfb
--- /dev/null
+++ b/src/mmo/fwd.hpp
@@ -0,0 +1,68 @@
+#pragma once
+// mmo/fwd.hpp - list of type names for mmo lib
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../sanity.hpp"
+
+
+namespace tmwa
+{
+// meh, add more when I feel like it
+class MapName;
+class CharName;
+class CharPair;
+
+class HumanTimeDiff;
+
+class AccountId;
+class CharId;
+class PartyId;
+class ItemUnkId;
+class ItemNameId;
+class GmLevel;
+
+class AccountName;
+class AccountPass;
+class AccountCrypt;
+class AccountEmail;
+class ServerName;
+class PartyName;
+class VarName;
+class MapName;
+class CharName;
+
+class Item;
+#if 0
+class Point;
+class SkillValue;
+#endif
+class GlobalReg;
+#if 0
+class CharKey;
+class CharData;
+class CharPair;
+#endif
+class Storage;
+#if 0
+class GM_Account;
+class PartyMember;
+#endif
+class PartyMost;
+class PartyPair;
+} // namespace tmwa
diff --git a/src/mmo/human_time_diff.cpp b/src/mmo/human_time_diff.cpp
index f2f720e..49a7664 100644
--- a/src/mmo/human_time_diff.cpp
+++ b/src/mmo/human_time_diff.cpp
@@ -19,3 +19,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa
diff --git a/src/mmo/human_time_diff.hpp b/src/mmo/human_time_diff.hpp
index 689b8d9..b5c19fb 100644
--- a/src/mmo/human_time_diff.hpp
+++ b/src/mmo/human_time_diff.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_HUMAN_TIME_DIFF_HPP
-#define TMWA_MMO_HUMAN_TIME_DIFF_HPP
+#pragma once
// human_time_diff.hpp - broken deltas
//
// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
@@ -19,12 +18,17 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../strings/xstring.hpp"
+#include <algorithm>
-# include "extract.hpp"
+#include "../strings/xstring.hpp"
+#include "extract.hpp"
+
+
+namespace tmwa
+{
struct HumanTimeDiff
{
short year, month, day, hour, minute, second;
@@ -61,26 +65,25 @@ bool extract(XString str, HumanTimeDiff *iv)
str = str.xislice_t(it2);
short *ptr = nullptr;
- if (suffix == "y" || suffix == "a")
+ if (suffix == "y"_s || suffix == "a"_s)
ptr = &iv->year;
- else if (suffix == "m")
+ else if (suffix == "m"_s)
ptr = &iv->month;
- else if (suffix == "j" || suffix == "d")
+ else if (suffix == "j"_s || suffix == "d"_s)
ptr = &iv->day;
- else if (suffix == "h")
+ else if (suffix == "h"_s)
ptr = &iv->hour;
- else if (suffix == "mn")
+ else if (suffix == "mn"_s)
ptr = &iv->minute;
- else if (suffix == "s")
+ else if (suffix == "s"_s)
ptr = &iv->second;
else
return false;
- if (number.startswith('+') && !number.startswith("+-"))
+ if (number.startswith('+') && !number.startswith("+-"_s))
number = number.xslice_t(1);
if (*ptr || !extract(number, ptr))
return false;
}
return true;
}
-
-#endif // TMWA_MMO_HUMAN_TIME_DIFF_HPP
+} // namespace tmwa
diff --git a/src/mmo/human_time_diff_test.cpp b/src/mmo/human_time_diff_test.cpp
index 138849b..c18599d 100644
--- a/src/mmo/human_time_diff_test.cpp
+++ b/src/mmo/human_time_diff_test.cpp
@@ -1,5 +1,5 @@
#include "human_time_diff.hpp"
-// human_time_diff.hpp - Testwuite for broken deltas
+// human_time_diff_test.cpp - Testwuite for broken deltas
//
// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
//
@@ -22,13 +22,16 @@
#include "../poison.hpp"
+
+namespace tmwa
+{
// a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s)
TEST(humantimediff, single)
{
HumanTimeDiff diff;
- EXPECT_TRUE(extract("42y", &diff));
+ EXPECT_TRUE(extract("42y"_s, &diff));
EXPECT_EQ(42, diff.year);
EXPECT_EQ(0, diff.month);
EXPECT_EQ(0, diff.day);
@@ -36,7 +39,7 @@ TEST(humantimediff, single)
EXPECT_EQ(0, diff.minute);
EXPECT_EQ(0, diff.second);
- EXPECT_TRUE(extract("42m", &diff));
+ EXPECT_TRUE(extract("42m"_s, &diff));
EXPECT_EQ(0, diff.year);
EXPECT_EQ(42, diff.month);
EXPECT_EQ(0, diff.day);
@@ -44,7 +47,7 @@ TEST(humantimediff, single)
EXPECT_EQ(0, diff.minute);
EXPECT_EQ(0, diff.second);
- EXPECT_TRUE(extract("42d", &diff));
+ EXPECT_TRUE(extract("42d"_s, &diff));
EXPECT_EQ(0, diff.year);
EXPECT_EQ(0, diff.month);
EXPECT_EQ(42, diff.day);
@@ -52,7 +55,7 @@ TEST(humantimediff, single)
EXPECT_EQ(0, diff.minute);
EXPECT_EQ(0, diff.second);
- EXPECT_TRUE(extract("42h", &diff));
+ EXPECT_TRUE(extract("42h"_s, &diff));
EXPECT_EQ(0, diff.year);
EXPECT_EQ(0, diff.month);
EXPECT_EQ(0, diff.day);
@@ -60,7 +63,7 @@ TEST(humantimediff, single)
EXPECT_EQ(0, diff.minute);
EXPECT_EQ(0, diff.second);
- EXPECT_TRUE(extract("42mn", &diff));
+ EXPECT_TRUE(extract("42mn"_s, &diff));
EXPECT_EQ(0, diff.year);
EXPECT_EQ(0, diff.month);
EXPECT_EQ(0, diff.day);
@@ -68,7 +71,7 @@ TEST(humantimediff, single)
EXPECT_EQ(42, diff.minute);
EXPECT_EQ(0, diff.second);
- EXPECT_TRUE(extract("42s", &diff));
+ EXPECT_TRUE(extract("42s"_s, &diff));
EXPECT_EQ(0, diff.year);
EXPECT_EQ(0, diff.month);
EXPECT_EQ(0, diff.day);
@@ -76,28 +79,29 @@ TEST(humantimediff, single)
EXPECT_EQ(0, diff.minute);
EXPECT_EQ(42, diff.second);
- EXPECT_TRUE(extract("+42y", &diff));
+ EXPECT_TRUE(extract("+42y"_s, &diff));
EXPECT_EQ(42, diff.year);
- EXPECT_TRUE(extract("-42y", &diff));
+ EXPECT_TRUE(extract("-42y"_s, &diff));
EXPECT_EQ(-42, diff.year);
- EXPECT_FALSE(extract("++42y", &diff));
- EXPECT_FALSE(extract("+-42y", &diff));
- EXPECT_FALSE(extract("-+42y", &diff));
- EXPECT_FALSE(extract("--42y", &diff));
- EXPECT_FALSE(extract("4+2y", &diff));
- EXPECT_FALSE(extract("42z", &diff));
+ EXPECT_FALSE(extract("++42y"_s, &diff));
+ EXPECT_FALSE(extract("+-42y"_s, &diff));
+ EXPECT_FALSE(extract("-+42y"_s, &diff));
+ EXPECT_FALSE(extract("--42y"_s, &diff));
+ EXPECT_FALSE(extract("4+2y"_s, &diff));
+ EXPECT_FALSE(extract("42z"_s, &diff));
}
TEST(humantimediff, multiple)
{
HumanTimeDiff diff;
- EXPECT_TRUE(extract("42y23m-2d", &diff));
+ EXPECT_TRUE(extract("42y23m-2d"_s, &diff));
EXPECT_EQ(42, diff.year);
EXPECT_EQ(23, diff.month);
EXPECT_EQ(-2, diff.day);
EXPECT_EQ(0, diff.hour);
EXPECT_EQ(0, diff.minute);
EXPECT_EQ(0, diff.second);
- EXPECT_FALSE(extract("1y2y", &diff));
+ EXPECT_FALSE(extract("1y2y"_s, &diff));
}
+} // namespace tmwa
diff --git a/src/mmo/ids.cpp b/src/mmo/ids.cpp
new file mode 100644
index 0000000..d40d5c3
--- /dev/null
+++ b/src/mmo/ids.cpp
@@ -0,0 +1,26 @@
+#include "ids.hpp"
+// ids.cpp - special integer classes for various object IDs
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa
diff --git a/src/mmo/ids.hpp b/src/mmo/ids.hpp
new file mode 100644
index 0000000..4e2b97c
--- /dev/null
+++ b/src/mmo/ids.hpp
@@ -0,0 +1,168 @@
+#pragma once
+// ids.hpp - special integer classes for various object IDs
+//
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../ints/little.hpp"
+#include "../ints/wrap.hpp"
+
+#include "extract.hpp"
+
+
+namespace tmwa
+{
+class Species : public Wrapped<uint16_t> { public: explicit operator bool() const = delete; bool operator !() const = delete; constexpr Species() : Wrapped<uint16_t>() {} protected: constexpr explicit Species(uint16_t a) : Wrapped<uint16_t>(a) {} };
+
+constexpr Species NEGATIVE_SPECIES = Species();
+
+inline
+bool extract(XString str, Species *w)
+{
+ // lots of data files use this
+ if (str == "-1"_s)
+ {
+ *w = NEGATIVE_SPECIES;
+ return true;
+ }
+ return extract(str, &w->_value);
+}
+
+
+class AccountId : public Wrapped<uint32_t> { public: constexpr AccountId() : Wrapped<uint32_t>() {} protected: constexpr explicit AccountId(uint32_t a) : Wrapped<uint32_t>(a) {} };
+class CharId : public Wrapped<uint32_t> { public: constexpr CharId() : Wrapped<uint32_t>() {} protected: constexpr explicit CharId(uint32_t a) : Wrapped<uint32_t>(a) {} };
+// important note: slave mobs synthesize PartyId as -BlockId of master
+class PartyId : public Wrapped<uint32_t> { public: constexpr PartyId() : Wrapped<uint32_t>() {} protected: constexpr explicit PartyId(uint32_t a) : Wrapped<uint32_t>(a) {} };
+class ItemNameId : public Wrapped<uint16_t> { public: constexpr ItemNameId() : Wrapped<uint16_t>() {} protected: constexpr explicit ItemNameId(uint16_t a) : Wrapped<uint16_t>(a) {} };
+
+class BlockId : public Wrapped<uint32_t> { public: constexpr BlockId() : Wrapped<uint32_t>() {} protected: constexpr explicit BlockId(uint32_t a) : Wrapped<uint32_t>(a) {} };
+
+class GmLevel
+{
+ uint32_t bits;
+
+ friend bool extract(XString str, GmLevel *lvl) { return extract(str, &lvl->bits); }
+ constexpr explicit
+ GmLevel(uint32_t b) : bits(b) {}
+ constexpr explicit
+ operator uint32_t() const { return bits; }
+
+ template<class T>
+ explicit
+ GmLevel(T) = delete;
+ template<class T, typename=typename std::enable_if<!std::is_same<T, uint32_t>::value && !std::is_same<T, bool>::value>::type>
+ explicit
+ operator T() = delete;
+public:
+ constexpr
+ GmLevel() : bits() {}
+ constexpr static
+ GmLevel from(uint32_t bits) { return GmLevel(bits); }
+ template<class T>
+ constexpr static
+ GmLevel from(T) = delete;
+
+ constexpr explicit
+ operator bool() const { return bits; }
+ constexpr
+ bool operator !() const { return !bits; }
+
+ // the argument is the level of a command
+ constexpr
+ bool satisfies(GmLevel perm) const { return bits >= perm.bits; }
+ // the argument is another player's gm level, for info commands
+ constexpr
+ bool detects(GmLevel other) const { return bits >= other.bits; }
+ // the argument is another player's gm level, for aggressive commands
+ constexpr
+ bool overwhelms(GmLevel other) const { return bits >= other.bits; }
+ // the argument is another potential permission level
+ constexpr
+ bool obsoletes(GmLevel plvl) const { return bits >= plvl.bits; }
+
+ constexpr
+ uint16_t get_public_word() const
+ {
+ return (bits == 60 || bits == 99) ? 0x0080 : 0;
+ }
+
+ constexpr
+ uint32_t get_all_bits() const
+ {
+ return bits;
+ }
+
+ friend constexpr
+ bool operator == (GmLevel l, GmLevel r)
+ {
+ return l.bits == r.bits;
+ }
+ friend constexpr
+ bool operator != (GmLevel l, GmLevel r)
+ {
+ return l.bits != r.bits;
+ }
+
+ friend
+ bool native_to_network(Byte *network, GmLevel native)
+ {
+ network->value = native.bits;
+ return true; // LIES. But this code is going away soon anyway
+ }
+ friend
+ bool network_to_native(GmLevel *native, Byte network)
+ {
+ native->bits = network.value;
+ return true; // LIES. But this code is going away soon anyway
+ }
+
+ // TODO kill this code too
+ friend
+ bool native_to_network(Little16 *network, GmLevel native)
+ {
+ uint16_t tmp = native.bits;
+ return native_to_network(network, tmp);
+ }
+ friend
+ bool network_to_native(GmLevel *native, Little16 network)
+ {
+ uint16_t tmp;
+ bool rv = network_to_native(&tmp, network);
+ native->bits = tmp;
+ return rv;
+ }
+
+ friend
+ bool native_to_network(Little32 *network, GmLevel native)
+ {
+ return native_to_network(network, native.bits);
+ }
+ friend
+ bool network_to_native(GmLevel *native, Little32 network)
+ {
+ return network_to_native(&native->bits, network);
+ }
+};
+
+inline
+uint32_t convert_for_printf(GmLevel g)
+{
+ return g.get_all_bits();
+}
+} // namespace tmwa
diff --git a/src/mmo/ip.cpp b/src/mmo/ip.cpp
deleted file mode 100644
index 146734a..0000000
--- a/src/mmo/ip.cpp
+++ /dev/null
@@ -1,114 +0,0 @@
-#include "ip.hpp"
-// ip.cpp - Implementation of IP address functions.
-//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include "../strings/xstring.hpp"
-#include "../strings/vstring.hpp"
-
-#include "../io/cxxstdio.hpp"
-
-#include "../poison.hpp"
-
-bool extract(XString str, IP4Address *rv)
-{
- if (str.endswith('.'))
- return false;
- uint8_t buf[4];
- if (extract(str, record<'.'>(&buf[0], &buf[1], &buf[2], &buf[3])))
- {
- *rv = IP4Address(buf);
- return true;
- }
- return false;
-}
-
-bool extract(XString str, IP4Mask *rv)
-{
- IP4Address a, m;
- unsigned b;
- XString l, r;
- if (str.endswith('/'))
- return false;
- if (extract(str, record<'/'>(&l, &r)))
- {
- // a.b.c.d/e.f.g.h or a.b.c.d/n
- if (!extract(l, &a))
- return false;
- if (extract(r, &m))
- {
- *rv = IP4Mask(a, m);
- return true;
- }
- if (!extract(r, &b) || b > 32)
- return false;
- }
- else
- {
- // a.b.c.d or a.b.c.d. or a.b.c. or a.b. or a.
- if (extract(str, &a))
- {
- *rv = IP4Mask(a, IP4_BROADCAST);
- return true;
- }
- if (!str.endswith('.'))
- return false;
- uint8_t d[4] {};
- if (extract(str, record<'.'>(&d[0], &d[1], &d[2], &d[3])))
- b = 32;
- else if (extract(str, record<'.'>(&d[0], &d[1], &d[2])))
- b = 24;
- else if (extract(str, record<'.'>(&d[0], &d[1])))
- b = 16;
- else if (extract(str, record<'.'>(&d[0])))
- b = 8;
- else
- return false;
- a = IP4Address(d);
- }
- // a is set; need to construct m from b
- if (b == 0)
- m = IP4Address();
- else if (b == 32)
- m = IP4_BROADCAST;
- else
- {
- uint32_t s = -1;
- s <<= (32 - b);
- m = IP4Address({
- static_cast<uint8_t>(s >> 24),
- static_cast<uint8_t>(s >> 16),
- static_cast<uint8_t>(s >> 8),
- static_cast<uint8_t>(s >> 0),
- });
- }
- *rv = IP4Mask(a, m);
- return true;
-}
-
-VString<15> convert_for_printf(IP4Address a_)
-{
- const uint8_t *a = a_.bytes();
- return STRNPRINTF(16, "%hhu.%hhu.%hhu.%hhu", a[0], a[1], a[2], a[3]);
-}
-
-VString<31> convert_for_printf(IP4Mask a)
-{
- return STRNPRINTF(32, "%s/%s",
- a.addr(), a.mask());
-}
diff --git a/src/mmo/ip.hpp b/src/mmo/ip.hpp
deleted file mode 100644
index a425710..0000000
--- a/src/mmo/ip.hpp
+++ /dev/null
@@ -1,164 +0,0 @@
-#ifndef TMWA_MMO_IP_HPP
-#define TMWA_MMO_IP_HPP
-// ip.hpp - classes to deal with IP addresses.
-//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# include "../sanity.hpp"
-
-# include <netinet/in.h>
-
-# include "../strings/fwd.hpp"
-
-# include "extract.hpp"
-
-// TODO - in the long run ports belong here also
-// and of course, IPv6 stuff.
-// But what about unix socket addresses?
-
-/// Helper function
-template<class T, size_t n>
-constexpr
-bool _ce_a_lt(T (&a)[n], T (&b)[n], size_t i=0)
-{
- return (i != n
- && (a[i] < b[i]
- || (a[i] == b[i]
- && _ce_a_lt(a, b, i + 1))));
-}
-
-/// A 32-bit Ipv4 address. Does not include a port.
-/// Guaranteed to be laid out like the network wants.
-class IP4Address
-{
- uint8_t _addr[4];
-public:
- constexpr
- IP4Address()
- : _addr{}
- {}
- constexpr explicit
- IP4Address(const uint8_t (&a)[4])
- : _addr{a[0], a[1], a[2], a[3]}
- {}
- explicit
- IP4Address(struct in_addr addr)
- {
- static_assert(sizeof(addr) == sizeof(_addr), "4 bytes");
- *this = IP4Address(reinterpret_cast<const uint8_t (&)[4]>(addr));
- }
- explicit
- operator struct in_addr() const
- {
- return reinterpret_cast<const struct in_addr&>(_addr);
- }
-
- constexpr friend
- IP4Address operator & (IP4Address l, IP4Address r)
- {
- return IP4Address({
- static_cast<uint8_t>(l._addr[0] & r._addr[0]),
- static_cast<uint8_t>(l._addr[1] & r._addr[1]),
- static_cast<uint8_t>(l._addr[2] & r._addr[2]),
- static_cast<uint8_t>(l._addr[3] & r._addr[3]),
- });
- }
-
- IP4Address& operator &= (IP4Address m)
- { return *this = *this & m; }
-
- const uint8_t *bytes() const
- { return _addr; }
-
- constexpr friend
- bool operator < (IP4Address l, IP4Address r)
- {
- return _ce_a_lt(l._addr, r._addr);
- }
-
- constexpr friend
- bool operator > (IP4Address l, IP4Address r)
- {
- return _ce_a_lt(r._addr, l._addr);
- }
-
- constexpr friend
- bool operator >= (IP4Address l, IP4Address r)
- {
- return !_ce_a_lt(l._addr, r._addr);
- }
-
- constexpr friend
- bool operator <= (IP4Address l, IP4Address r)
- {
- return !_ce_a_lt(r._addr, l._addr);
- }
-
- constexpr friend
- bool operator == (IP4Address l, IP4Address r)
- {
- return !(l < r || r < l);
- }
-
- constexpr friend
- bool operator != (IP4Address l, IP4Address r)
- {
- return (l < r || r < l);
- }
-};
-
-class IP4Mask
-{
- IP4Address _addr, _mask;
-public:
- constexpr
- IP4Mask() : _addr(), _mask()
- {}
- constexpr
- IP4Mask(IP4Address a, IP4Address m) : _addr(a & m), _mask(m)
- {}
-
- constexpr
- IP4Address addr() const
- { return _addr; }
- constexpr
- IP4Address mask() const
- { return _mask; }
-
- constexpr
- bool covers(IP4Address a) const
- {
- return (a & _mask) == _addr;
- }
-};
-
-
-constexpr
-IP4Address IP4_LOCALHOST({127, 0, 0, 1});
-constexpr
-IP4Address IP4_BROADCAST({255, 255, 255, 255});
-
-
-VString<15> convert_for_printf(IP4Address a);
-VString<31> convert_for_printf(IP4Mask m);
-
-bool extract(XString str, IP4Address *iv);
-
-bool extract(XString str, IP4Mask *iv);
-
-#endif // TMWA_MMO_IP_HPP
diff --git a/src/mmo/ip.py b/src/mmo/ip.py
deleted file mode 100644
index e6a8183..0000000
--- a/src/mmo/ip.py
+++ /dev/null
@@ -1,14 +0,0 @@
-class IP4Address(object):
- ''' print an IP4Address
- '''
- __slots__ = ('_value')
- name = 'IP4Address'
- enabled = True
-
- def __init__(self, value):
- self._value = value
-
- def to_string(self):
- addr = self._value['_addr']
- addr = tuple(int(addr[i]) for i in range(4))
- return '%d.%d.%d.%d' % addr
diff --git a/src/mmo/ip_test.cpp b/src/mmo/ip_test.cpp
deleted file mode 100644
index 8e50453..0000000
--- a/src/mmo/ip_test.cpp
+++ /dev/null
@@ -1,352 +0,0 @@
-#include "ip.hpp"
-// ip_test.cpp - Testsuite for implementation of IP address functions.
-//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <gtest/gtest.h>
-
-#include "../io/cxxstdio.hpp"
-
-#include "../poison.hpp"
-
-#define CB(X) (std::integral_constant<bool, (X)>::value)
-TEST(ip4addr, cmp)
-{
- constexpr static
- IP4Address a = IP4_LOCALHOST;
- constexpr static
- IP4Address b = IP4_BROADCAST;
-
- EXPECT_FALSE(CB(a < a));
- EXPECT_TRUE (CB(a < b));
- EXPECT_FALSE(CB(b < a));
- EXPECT_FALSE(CB(b < b));
-
- EXPECT_FALSE(CB(a > a));
- EXPECT_FALSE(CB(a > b));
- EXPECT_TRUE (CB(b > a));
- EXPECT_FALSE(CB(b > b));
-
- EXPECT_TRUE (CB(a <= a));
- EXPECT_TRUE (CB(a <= b));
- EXPECT_FALSE(CB(b <= a));
- EXPECT_TRUE (CB(b <= b));
-
- EXPECT_TRUE (CB(a >= a));
- EXPECT_FALSE(CB(a >= b));
- EXPECT_TRUE (CB(b >= a));
- EXPECT_TRUE (CB(b >= b));
-
- EXPECT_TRUE (CB(a == a));
- EXPECT_FALSE(CB(a == b));
- EXPECT_FALSE(CB(b == a));
- EXPECT_TRUE (CB(b == b));
-
- EXPECT_FALSE(CB(a != a));
- EXPECT_TRUE (CB(a != b));
- EXPECT_TRUE (CB(b != a));
- EXPECT_FALSE(CB(b != b));
-}
-
-TEST(ip4addr, str)
-{
- IP4Address a;
- EXPECT_EQ("0.0.0.0", STRNPRINTF(17, "%s", a));
- EXPECT_EQ("127.0.0.1", STRNPRINTF(17, "%s", IP4_LOCALHOST));
- EXPECT_EQ("255.255.255.255", STRNPRINTF(17, "%s", IP4_BROADCAST));
-}
-
-TEST(ip4addr, extract)
-{
- IP4Address a;
- EXPECT_TRUE(extract("0.0.0.0", &a));
- EXPECT_EQ("0.0.0.0", STRNPRINTF(16, "%s", a));
- EXPECT_TRUE(extract("127.0.0.1", &a));
- EXPECT_EQ("127.0.0.1", STRNPRINTF(16, "%s", a));
- EXPECT_TRUE(extract("255.255.255.255", &a));
- EXPECT_EQ("255.255.255.255", STRNPRINTF(16, "%s", a));
- EXPECT_TRUE(extract("1.2.3.4", &a));
- EXPECT_EQ("1.2.3.4", STRNPRINTF(16, "%s", a));
-
- EXPECT_FALSE(extract("1.2.3.4.5", &a));
- EXPECT_FALSE(extract("1.2.3.4.", &a));
- EXPECT_FALSE(extract("1.2.3.", &a));
- EXPECT_FALSE(extract("1.2.3", &a));
- EXPECT_FALSE(extract("1.2.", &a));
- EXPECT_FALSE(extract("1.2", &a));
- EXPECT_FALSE(extract("1.", &a));
- EXPECT_FALSE(extract("1", &a));
- EXPECT_FALSE(extract("", &a));
-}
-
-
-TEST(ip4mask, body)
-{
- IP4Mask m;
- EXPECT_EQ(IP4Address(), m.addr());
- EXPECT_EQ(IP4Address(), m.mask());
- m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST);
- EXPECT_EQ(IP4_LOCALHOST, m.addr());
- EXPECT_EQ(IP4_BROADCAST, m.mask());
-}
-
-TEST(ip4mask, str)
-{
- IP4Mask m;
- EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(33, "%s", m));
- m = IP4Mask(IP4_LOCALHOST, IP4_BROADCAST);
- EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(33, "%s", m));
-}
-
-TEST(ip4mask, extract)
-{
- IP4Mask m;
- EXPECT_FALSE(extract("9.8.7.6/33", &m));
- EXPECT_FALSE(extract("9.8.7.6.5", &m));
- EXPECT_FALSE(extract("9.8.7.6/", &m));
- EXPECT_FALSE(extract("9.8.7", &m));
- EXPECT_FALSE(extract("9.8", &m));
- EXPECT_FALSE(extract("9", &m));
-
- EXPECT_TRUE(extract("127.0.0.1", &m));
- EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("127.0.0.1.", &m));
- EXPECT_EQ("127.0.0.1/255.255.255.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("127.0.0.", &m));
- EXPECT_EQ("127.0.0.0/255.255.255.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("127.0.", &m));
- EXPECT_EQ("127.0.0.0/255.255.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("127.", &m));
- EXPECT_EQ("127.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m));
-
- EXPECT_TRUE(extract("1.2.3.4/255.255.255.255", &m));
- EXPECT_EQ("1.2.3.4/255.255.255.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.2.3.0/255.255.255.0", &m));
- EXPECT_EQ("1.2.3.0/255.255.255.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.2.0.4/255.255.0.255", &m));
- EXPECT_EQ("1.2.0.4/255.255.0.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.2.0.0/255.255.0.0", &m));
- EXPECT_EQ("1.2.0.0/255.255.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.0.3.4/255.0.255.255", &m));
- EXPECT_EQ("1.0.3.4/255.0.255.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.0.3.0/255.0.255.0", &m));
- EXPECT_EQ("1.0.3.0/255.0.255.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.0.0.4/255.0.0.255", &m));
- EXPECT_EQ("1.0.0.4/255.0.0.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("1.0.0.0/255.0.0.0", &m));
- EXPECT_EQ("1.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.2.3.4/0.255.255.255", &m));
- EXPECT_EQ("0.2.3.4/0.255.255.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.2.3.0/0.255.255.0", &m));
- EXPECT_EQ("0.2.3.0/0.255.255.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.2.0.4/0.255.0.255", &m));
- EXPECT_EQ("0.2.0.4/0.255.0.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.2.0.0/0.255.0.0", &m));
- EXPECT_EQ("0.2.0.0/0.255.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.3.4/0.0.255.255", &m));
- EXPECT_EQ("0.0.3.4/0.0.255.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.3.0/0.0.255.0", &m));
- EXPECT_EQ("0.0.3.0/0.0.255.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.4/0.0.0.255", &m));
- EXPECT_EQ("0.0.0.4/0.0.0.255", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/0.0.0.0", &m));
- EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(32, "%s", m));
-
- // please don't do this
- EXPECT_TRUE(extract("120.248.200.217/89.57.126.5", &m));
- EXPECT_EQ("88.56.72.1/89.57.126.5", STRNPRINTF(32, "%s", m));
-
- EXPECT_TRUE(extract("0.0.0.0/32", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.255", STRNPRINTF(32, "%s", m));
-
- EXPECT_TRUE(extract("0.0.0.0/31", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.254", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/30", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.252", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/29", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.248", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/28", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.240", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/27", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.224", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/26", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.192", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/25", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.128", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/24", &m));
- EXPECT_EQ("0.0.0.0/255.255.255.0", STRNPRINTF(32, "%s", m));
-
- EXPECT_TRUE(extract("0.0.0.0/23", &m));
- EXPECT_EQ("0.0.0.0/255.255.254.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/22", &m));
- EXPECT_EQ("0.0.0.0/255.255.252.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/21", &m));
- EXPECT_EQ("0.0.0.0/255.255.248.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/20", &m));
- EXPECT_EQ("0.0.0.0/255.255.240.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/19", &m));
- EXPECT_EQ("0.0.0.0/255.255.224.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/18", &m));
- EXPECT_EQ("0.0.0.0/255.255.192.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/17", &m));
- EXPECT_EQ("0.0.0.0/255.255.128.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/16", &m));
- EXPECT_EQ("0.0.0.0/255.255.0.0", STRNPRINTF(32, "%s", m));
-
- EXPECT_TRUE(extract("0.0.0.0/15", &m));
- EXPECT_EQ("0.0.0.0/255.254.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/14", &m));
- EXPECT_EQ("0.0.0.0/255.252.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/13", &m));
- EXPECT_EQ("0.0.0.0/255.248.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/12", &m));
- EXPECT_EQ("0.0.0.0/255.240.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/11", &m));
- EXPECT_EQ("0.0.0.0/255.224.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/10", &m));
- EXPECT_EQ("0.0.0.0/255.192.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/9", &m));
- EXPECT_EQ("0.0.0.0/255.128.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/8", &m));
- EXPECT_EQ("0.0.0.0/255.0.0.0", STRNPRINTF(32, "%s", m));
-
- EXPECT_TRUE(extract("0.0.0.0/7", &m));
- EXPECT_EQ("0.0.0.0/254.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/6", &m));
- EXPECT_EQ("0.0.0.0/252.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/5", &m));
- EXPECT_EQ("0.0.0.0/248.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/4", &m));
- EXPECT_EQ("0.0.0.0/240.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/3", &m));
- EXPECT_EQ("0.0.0.0/224.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/2", &m));
- EXPECT_EQ("0.0.0.0/192.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/1", &m));
- EXPECT_EQ("0.0.0.0/128.0.0.0", STRNPRINTF(32, "%s", m));
- EXPECT_TRUE(extract("0.0.0.0/0", &m));
- EXPECT_EQ("0.0.0.0/0.0.0.0", STRNPRINTF(32, "%s", m));
-}
-
-TEST(ip4mask, cover)
-{
- IP4Address a;
- IP4Address b = IP4_BROADCAST;
- IP4Address l = IP4_LOCALHOST;
- IP4Address h({127, 255, 255, 255});
- IP4Address p24l({10, 0, 0, 0});
- IP4Address p24h({10, 255, 255, 255});
- IP4Address p20l({172, 16, 0, 0});
- IP4Address p20h({172, 31, 255, 255});
- IP4Address p16l({192, 168, 0, 0});
- IP4Address p16h({192, 168, 255, 255});
- IP4Mask m;
- EXPECT_TRUE(m.covers(a));
- EXPECT_TRUE(m.covers(b));
- EXPECT_TRUE(m.covers(l));
- EXPECT_TRUE(m.covers(h));
- EXPECT_TRUE(m.covers(p24l));
- EXPECT_TRUE(m.covers(p24h));
- EXPECT_TRUE(m.covers(p20l));
- EXPECT_TRUE(m.covers(p20h));
- EXPECT_TRUE(m.covers(p16l));
- EXPECT_TRUE(m.covers(p16h));
- m = IP4Mask(l, a);
- EXPECT_TRUE(m.covers(a));
- EXPECT_TRUE(m.covers(b));
- EXPECT_TRUE(m.covers(l));
- EXPECT_TRUE(m.covers(h));
- EXPECT_TRUE(m.covers(p24l));
- EXPECT_TRUE(m.covers(p24h));
- EXPECT_TRUE(m.covers(p20l));
- EXPECT_TRUE(m.covers(p20h));
- EXPECT_TRUE(m.covers(p16l));
- EXPECT_TRUE(m.covers(p16h));
- m = IP4Mask(l, b);
- EXPECT_FALSE(m.covers(a));
- EXPECT_FALSE(m.covers(b));
- EXPECT_TRUE(m.covers(l));
- EXPECT_FALSE(m.covers(h));
- EXPECT_FALSE(m.covers(p24l));
- EXPECT_FALSE(m.covers(p24h));
- EXPECT_FALSE(m.covers(p20l));
- EXPECT_FALSE(m.covers(p20h));
- EXPECT_FALSE(m.covers(p16l));
- EXPECT_FALSE(m.covers(p16h));
-
- // but the really useful ones are with partial masks
- m = IP4Mask(IP4Address({10, 0, 0, 0}), IP4Address({255, 0, 0, 0}));
- EXPECT_FALSE(m.covers(a));
- EXPECT_FALSE(m.covers(b));
- EXPECT_FALSE(m.covers(l));
- EXPECT_FALSE(m.covers(h));
- EXPECT_TRUE(m.covers(p24l));
- EXPECT_TRUE(m.covers(p24h));
- EXPECT_FALSE(m.covers(p20l));
- EXPECT_FALSE(m.covers(p20h));
- EXPECT_FALSE(m.covers(p16l));
- EXPECT_FALSE(m.covers(p16h));
- EXPECT_FALSE(m.covers(IP4Address({9, 255, 255, 255})));
- EXPECT_FALSE(m.covers(IP4Address({11, 0, 0, 0})));
- m = IP4Mask(IP4Address({127, 0, 0, 0}), IP4Address({255, 0, 0, 0}));
- EXPECT_FALSE(m.covers(a));
- EXPECT_FALSE(m.covers(b));
- EXPECT_TRUE(m.covers(l));
- EXPECT_TRUE(m.covers(h));
- EXPECT_FALSE(m.covers(p24l));
- EXPECT_FALSE(m.covers(p24h));
- EXPECT_FALSE(m.covers(p20l));
- EXPECT_FALSE(m.covers(p20h));
- EXPECT_FALSE(m.covers(p16l));
- EXPECT_FALSE(m.covers(p16h));
- EXPECT_FALSE(m.covers(IP4Address({126, 255, 255, 255})));
- EXPECT_FALSE(m.covers(IP4Address({128, 0, 0, 0})));
- m = IP4Mask(IP4Address({172, 16, 0, 0}), IP4Address({255, 240, 0, 0}));
- EXPECT_FALSE(m.covers(a));
- EXPECT_FALSE(m.covers(b));
- EXPECT_FALSE(m.covers(l));
- EXPECT_FALSE(m.covers(h));
- EXPECT_FALSE(m.covers(p24l));
- EXPECT_FALSE(m.covers(p24h));
- EXPECT_TRUE(m.covers(p20l));
- EXPECT_TRUE(m.covers(p20h));
- EXPECT_FALSE(m.covers(p16l));
- EXPECT_FALSE(m.covers(p16h));
- EXPECT_FALSE(m.covers(IP4Address({172, 15, 255, 255})));
- EXPECT_FALSE(m.covers(IP4Address({172, 32, 0, 0})));
- m = IP4Mask(IP4Address({192, 168, 0, 0}), IP4Address({255, 255, 0, 0}));
- EXPECT_FALSE(m.covers(a));
- EXPECT_FALSE(m.covers(b));
- EXPECT_FALSE(m.covers(l));
- EXPECT_FALSE(m.covers(h));
- EXPECT_FALSE(m.covers(p24l));
- EXPECT_FALSE(m.covers(p24h));
- EXPECT_FALSE(m.covers(p20l));
- EXPECT_FALSE(m.covers(p20h));
- EXPECT_TRUE(m.covers(p16l));
- EXPECT_TRUE(m.covers(p16h));
- EXPECT_FALSE(m.covers(IP4Address({192, 167, 255, 255})));
- EXPECT_FALSE(m.covers(IP4Address({192, 169, 0, 0})));
-
- // OTOH this is crazy
- EXPECT_TRUE(extract("120.248.200.217/89.57.126.5", &m));
- EXPECT_TRUE(m.covers(IP4Address({120, 248, 200, 217})));
- EXPECT_TRUE(m.covers(IP4Address({88, 56, 72, 1})));
- EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 0})));
- EXPECT_FALSE(m.covers(IP4Address({88, 56, 72, 255})));
-}
diff --git a/src/mmo/md5more.cpp b/src/mmo/md5more.cpp
index 3fce5c7..4e5d2da 100644
--- a/src/mmo/md5more.cpp
+++ b/src/mmo/md5more.cpp
@@ -20,14 +20,24 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
+#include <algorithm>
+
#include "../compat/rawmem.hpp"
#include "../generic/random.hpp"
#include "../io/cxxstdio.hpp"
+#include "../io/read.hpp"
+
+#include "../net/ip.hpp"
+
+#include "../mmo/mmo.hpp"
#include "../poison.hpp"
+
+namespace tmwa
+{
#define X block.data
// TODO - refactor MD5 into a stream, and merge the implementations
@@ -103,7 +113,7 @@ AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt)
VString<31> obuf;
// This truncates the string, but we have to keep it like that for compatibility
- SNPRINTF(obuf, 32, "!%s$%s", salt, tbuf3);
+ SNPRINTF(obuf, 32, "!%s$%s"_fmt, salt, tbuf3);
return stringish<AccountCrypt>(obuf);
}
@@ -134,7 +144,7 @@ IP4Address MD5_ip(IP4Address ip)
// MD5sum a secret + the IP address
VString<31> ipbuf;
- SNPRINTF(ipbuf, 32, "%s %s", ip, secret);
+ SNPRINTF(ipbuf, 32, "%s %s"_fmt, ip, secret);
md5_binary obuf;
MD5_to_bin(MD5_from_string(ipbuf), obuf);
@@ -146,3 +156,4 @@ IP4Address MD5_ip(IP4Address ip)
static_cast<uint8_t>(obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]),
});
}
+} // namespace tmwa
diff --git a/src/mmo/md5more.hpp b/src/mmo/md5more.hpp
index b1da783..7d50713 100644
--- a/src/mmo/md5more.hpp
+++ b/src/mmo/md5more.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_MD5MORE_HPP
-#define TMWA_MMO_MD5MORE_HPP
+#pragma once
// md5more.hpp - Non-basic MD5 functions.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,15 +20,17 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../generic/md5.hpp"
+#include "../generic/md5.hpp"
-# include "../io/read.hpp"
+#include "../io/fwd.hpp"
-# include "ip.hpp"
-# include "mmo.hpp"
+#include "../net/fwd.hpp"
+
+namespace tmwa
+{
MD5_state MD5_from_FILE(io::ReadFile& in);
// whoever wrote this fails basic understanding of
@@ -44,5 +45,4 @@ bool pass_ok(AccountPass password, AccountCrypt crypted);
/// This returns an IP4Address because it is configurable whether it gets called at all
IP4Address MD5_ip(IP4Address ip);
-
-#endif // TMWA_MMO_MD5MORE_HPP
+} // namespace tmwa
diff --git a/src/mmo/mmo.cpp b/src/mmo/mmo.cpp
index 8bf7edf..aafa431 100644
--- a/src/mmo/mmo.cpp
+++ b/src/mmo/mmo.cpp
@@ -19,3 +19,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa
diff --git a/src/mmo/mmo.hpp b/src/mmo/mmo.hpp
index c9d62ca..cfa278d 100644
--- a/src/mmo/mmo.hpp
+++ b/src/mmo/mmo.hpp
@@ -1,6 +1,5 @@
-#ifndef TMWA_MMO_MMO_HPP
-#define TMWA_MMO_MMO_HPP
-// mmo.hpp - Huge mess of structures and constants.
+#pragma once
+// mmo.hpp - Huge mess of structures.
//
// Copyright © ????-2004 Athena Dev Teams
// Copyright © 2004-2011 The Mana World Development Team
@@ -21,347 +20,25 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include "../compat/memory.hpp"
+#include "../compat/memory.hpp"
-# include "../strings/vstring.hpp"
+#include "../proto2/types.hpp"
-# include "../generic/enum.hpp"
-# include "timer.t.hpp"
-
-// affects CharName
-# define NAME_IGNORING_CASE 1
-
-constexpr int FIFOSIZE_SERVERLINK = 256 * 1024;
-
-constexpr int MAX_MAP_PER_SERVER = 512;
-constexpr int MAX_INVENTORY = 100;
-constexpr int MAX_AMOUNT = 30000;
-constexpr int MAX_ZENY = 1000000000; // 1G zeny
-constexpr int TRADE_MAX = 10;
-
-enum class SkillID : uint16_t;
-constexpr SkillID MAX_SKILL = SkillID(474); // not 450
-constexpr SkillID get_enum_min_value(SkillID) { return SkillID(); }
-constexpr SkillID get_enum_max_value(SkillID) { return MAX_SKILL; }
-
-constexpr int GLOBAL_REG_NUM = 96;
-constexpr int ACCOUNT_REG_NUM = 16;
-constexpr int ACCOUNT_REG2_NUM = 16;
-constexpr interval_t DEFAULT_WALK_SPEED = std::chrono::milliseconds(150);
-constexpr interval_t MIN_WALK_SPEED = interval_t::zero();
-constexpr interval_t MAX_WALK_SPEED = std::chrono::seconds(1);
-constexpr int MAX_STORAGE = 300;
-constexpr int MAX_PARTY = 12;
-
-# define MIN_HAIR_STYLE battle_config.min_hair_style
-# define MAX_HAIR_STYLE battle_config.max_hair_style
-# define MIN_HAIR_COLOR battle_config.min_hair_color
-# define MAX_HAIR_COLOR battle_config.max_hair_color
-# define MIN_CLOTH_COLOR battle_config.min_cloth_color
-# define MAX_CLOTH_COLOR battle_config.max_cloth_color
-
-template<class T, size_t n>
-struct Array
+namespace tmwa
{
- T data[n];
-public:
- T& operator [](size_t i) { assert (i < n); return data[i]; }
- const T& operator [](size_t i) const { assert (i < n); return data[i]; }
-
- T *begin() { return data + 0; }
- T *end() { return data + n; }
- const T *begin() const { return data + 0; }
- const T *end() const { return data + n; }
-};
-
-struct AccountName : VString<23> {};
-struct AccountPass : VString<23> {};
-struct AccountCrypt : VString<39> {};
-struct AccountEmail : VString<39> {};
-struct ServerName : VString<19> {};
-struct PartyName : VString<23> {};
-struct VarName : VString<31> {};
-
-# define DEFAULT_EMAIL stringish<AccountEmail>("a@a.com")
-
-// It is decreed: a mapname shall not contain an extension
-class MapName : public strings::_crtp_string<MapName, MapName, strings::ZPair>
-{
- VString<15> _impl;
-public:
- MapName() = default;
- MapName(VString<15> v) : _impl(v.xislice_h(std::find(v.begin(), v.end(), '.'))) {}
-
- iterator begin() const { return &*_impl.begin(); }
- iterator end() const { return &*_impl.end(); }
- const char *c_str() const { return _impl.c_str(); }
-
- operator RString() const { return _impl; }
- operator AString() const { return _impl; }
- operator TString() const { return _impl; }
- operator SString() const { return _impl; }
- operator ZString() const { return _impl; }
- operator XString() const { return _impl; }
-};
-template<>
inline
-MapName stringish<MapName>(VString<15> iv)
+bool operator == (const SkillValue& l, const SkillValue& r)
{
- return iv;
+ return l.lv == r.lv && l.flags == r.flags;
}
inline
-const char *decay_for_printf(const MapName& vs) { return vs.c_str(); }
-
-// It is decreed: a charname is sometimes case sensitive
-struct CharName
+bool operator != (const SkillValue& l, const SkillValue& r)
{
-private:
- VString<23> _impl;
-public:
- CharName() = default;
- explicit CharName(VString<23> name)
- : _impl(name)
- {}
-
- VString<23> to__actual() const
- {
- return _impl;
- }
- VString<23> to__lower() const
- {
- return _impl.to_lower();
- }
- VString<23> to__upper() const
- {
- return _impl.to_upper();
- }
- VString<23> to__canonical() const
- {
-# if NAME_IGNORING_CASE == 0
- return to__actual();
-# endif
-# if NAME_IGNORING_CASE == 1
- return to__lower();
-# endif
- }
-
- friend bool operator == (const CharName& l, const CharName& r)
- { return l.to__canonical() == r.to__canonical(); }
- friend bool operator != (const CharName& l, const CharName& r)
- { return l.to__canonical() != r.to__canonical(); }
- friend bool operator < (const CharName& l, const CharName& r)
- { return l.to__canonical() < r.to__canonical(); }
- friend bool operator <= (const CharName& l, const CharName& r)
- { return l.to__canonical() <= r.to__canonical(); }
- friend bool operator > (const CharName& l, const CharName& r)
- { return l.to__canonical() > r.to__canonical(); }
- friend bool operator >= (const CharName& l, const CharName& r)
- { return l.to__canonical() >= r.to__canonical(); }
-
- friend
- VString<23> convert_for_printf(const CharName& vs) { return vs.to__actual(); }
-};
-template<>
-inline
-CharName stringish<CharName>(VString<23> iv)
-{
- return CharName(iv);
-}
-
-namespace e
-{
-enum class EPOS : uint16_t
-{
- ZERO = 0x0000,
-
- LEGS = 0x0001,
- WEAPON = 0x0002,
- GLOVES = 0x0004,
- CAPE = 0x0008,
- MISC1 = 0x0010,
- SHIELD = 0x0020,
- SHOES = 0x0040,
- MISC2 = 0x0080,
- HAT = 0x0100,
- TORSO = 0x0200,
-
- ARROW = 0x8000,
-};
-ENUM_BITWISE_OPERATORS(EPOS)
-
-constexpr EPOS get_enum_min_value(EPOS) { return EPOS(0x0000); }
-constexpr EPOS get_enum_max_value(EPOS) { return EPOS(0xffff); }
-}
-using e::EPOS;
-
-struct item
-{
- int id;
- short nameid;
- short amount;
- EPOS equip;
-};
-
-struct point
-{
- MapName map_;
- short x, y;
-};
-
-namespace e
-{
-enum class SkillFlags : uint16_t;
+ return !(l == r);
}
-using e::SkillFlags;
-
-struct skill_value
-{
- unsigned short lv;
- SkillFlags flags;
-
- friend bool operator == (const skill_value& l, const skill_value& r)
- {
- return l.lv == r.lv && l.flags == r.flags;
- }
- friend bool operator != (const skill_value& l, const skill_value& r)
- {
- return !(l == r);
- }
-};
-
-struct global_reg
-{
- VarName str;
- int value;
-};
-
-// Option and Opt1..3 in map.hpp
-namespace e
-{
-enum class Option : uint16_t;
-constexpr Option get_enum_min_value(Option) { return Option(0x0000); }
-constexpr Option get_enum_max_value(Option) { return Option(0xffff); }
-}
-using e::Option;
-
-enum class ATTR
-{
- STR = 0,
- AGI = 1,
- VIT = 2,
- INT = 3,
- DEX = 4,
- LUK = 5,
-
- COUNT = 6,
-};
-
-constexpr ATTR ATTRs[6] =
-{
- ATTR::STR,
- ATTR::AGI,
- ATTR::VIT,
- ATTR::INT,
- ATTR::DEX,
- ATTR::LUK,
-};
-
-enum class ItemLook : uint16_t
-{
- NONE = 0,
- BLADE = 1, // or some other common weapons
- _2,
- SETZER_AND_SCYTHE = 3,
- _6,
- STAFF = 10,
- BOW = 11,
- _13 = 13,
- _14 = 14,
- _16 = 16,
- SINGLE_HANDED_COUNT = 17,
-
- DUAL_BLADE = 0x11,
- DUAL_2 = 0x12,
- DUAL_6 = 0x13,
- DUAL_12 = 0x14,
- DUAL_16 = 0x15,
- DUAL_26 = 0x16,
-};
-
-enum class SEX : uint8_t
-{
- FEMALE = 0,
- MALE = 1,
- // For items. This is also used as error, sometime.
- NEUTRAL = 2,
-};
-inline
-char sex_to_char(SEX sex)
-{
- switch (sex)
- {
- case SEX::FEMALE: return 'F';
- case SEX::MALE: return 'M';
- default: return '\0';
- }
-}
-inline
-SEX sex_from_char(char c)
-{
- switch (c)
- {
- case 'F': return SEX::FEMALE;
- case 'M': return SEX::MALE;
- default: return SEX::NEUTRAL;
- }
-}
-
-struct CharKey
-{
- CharName name;
- int account_id;
- int char_id;
- unsigned char char_num;
-};
-
-struct CharData
-{
- int partner_id;
-
- int base_exp, job_exp, zeny;
-
- short species;
- short status_point, skill_point;
- int hp, max_hp, sp, max_sp;
- Option option;
- short karma, manner;
- short hair, hair_color, clothes_color;
- int party_id;
-
- ItemLook weapon;
- short shield;
- short head_top, head_mid, head_bottom;
-
- unsigned char base_level, job_level;
- earray<short, ATTR, ATTR::COUNT> attrs;
- SEX sex;
-
- unsigned long mapip;
- unsigned int mapport;
-
- struct point last_point, save_point;
- Array<struct item, MAX_INVENTORY> inventory;
- earray<skill_value, SkillID, MAX_SKILL> skill;
- int global_reg_num;
- Array<struct global_reg, GLOBAL_REG_NUM> global_reg;
- int account_reg_num;
- Array<struct global_reg, ACCOUNT_REG_NUM> account_reg;
- int account_reg2_num;
- Array<struct global_reg, ACCOUNT_REG2_NUM> account_reg2;
-};
struct CharPair
{
@@ -373,37 +50,20 @@ struct CharPair
{}
};
-struct storage
-{
- int dirty;
- int account_id;
- short storage_status;
- short storage_amount;
- Array<struct item, MAX_STORAGE> storage_;
-};
-
struct GM_Account
{
- int account_id;
- uint8_t level;
+ AccountId account_id;
+ GmLevel level;
};
-struct party_member
+struct PartyPair
{
- int account_id;
- CharName name;
- MapName map;
- int leader, online, lv;
- struct map_session_data *sd;
-};
+ PartyId party_id = {};
+ PartyMost *party_most = {};
-struct party
-{
- int party_id;
- PartyName name;
- int exp;
- int item;
- Array<struct party_member, MAX_PARTY> member;
+ explicit
+ operator bool() const { return party_most; }
+ bool operator !() const { return !party_most; }
+ PartyMost *operator->() const { return party_most; }
};
-
-#endif // TMWA_MMO_MMO_HPP
+} // namespace tmwa
diff --git a/src/mmo/socket.cpp b/src/mmo/socket.cpp
deleted file mode 100644
index 1e294bd..0000000
--- a/src/mmo/socket.cpp
+++ /dev/null
@@ -1,508 +0,0 @@
-#include "socket.hpp"
-// socket.cpp - Network event system.
-//
-// Copyright © ????-2004 Athena Dev Teams
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-// Copyright © 2013 MadCamel
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
-#include <sys/socket.h>
-//#include <sys/types.h>
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <cstdlib>
-#include <cstring>
-#include <ctime>
-
-#include "../io/cxxstdio.hpp"
-#include "core.hpp"
-#include "timer.hpp"
-#include "utils.hpp"
-
-#include "../poison.hpp"
-
-static
-io::FD_Set readfds;
-static
-int fd_max;
-
-static
-const uint32_t RFIFO_SIZE = 65536;
-static
-const uint32_t WFIFO_SIZE = 65536;
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-static
-std::array<std::unique_ptr<Session>, FD_SETSIZE> session;
-#pragma GCC diagnostic pop
-
-Session::Session(SessionIO io, SessionParsers p)
-: created()
-, connected()
-, eof()
-, timed_close()
-, rdata(), wdata()
-, max_rdata(), max_wdata()
-, rdata_size(), wdata_size()
-, rdata_pos()
-, client_ip()
-, func_recv()
-, func_send()
-, func_parse()
-, func_delete()
-, for_inferior()
-, session_data()
-, fd()
-{
- set_io(io);
- set_parsers(p);
-}
-void Session::set_io(SessionIO io)
-{
- func_send = io.func_send;
- func_recv = io.func_recv;
-}
-void Session::set_parsers(SessionParsers p)
-{
- func_parse = p.func_parse;
- func_delete = p.func_delete;
-}
-
-
-void set_session(io::FD fd, std::unique_ptr<Session> sess)
-{
- int f = fd.uncast_dammit();
- assert (0 <= f && f < FD_SETSIZE);
- session[f] = std::move(sess);
-}
-Session *get_session(io::FD fd)
-{
- int f = fd.uncast_dammit();
- if (0 <= f && f < FD_SETSIZE)
- return session[f].get();
- return nullptr;
-}
-void reset_session(io::FD fd)
-{
- int f = fd.uncast_dammit();
- assert (0 <= f && f < FD_SETSIZE);
- session[f] = nullptr;
-}
-int get_fd_max() { return fd_max; }
-IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds()
-{
- return {io::FD::cast_dammit(0), io::FD::cast_dammit(fd_max)};
-}
-
-/// clean up by discarding handled bytes
-inline
-void RFIFOFLUSH(Session *s)
-{
- really_memmove(&s->rdata[0], &s->rdata[s->rdata_pos], RFIFOREST(s));
- s->rdata_size = RFIFOREST(s);
- s->rdata_pos = 0;
-}
-
-/// how much room there is to read more data
-inline
-size_t RFIFOSPACE(Session *s)
-{
- return s->max_rdata - s->rdata_size;
-}
-
-
-/// Read from socket to the queue
-static
-void recv_to_fifo(Session *s)
-{
- ssize_t len = s->fd.read(&s->rdata[s->rdata_size],
- RFIFOSPACE(s));
-
- if (len > 0)
- {
- s->rdata_size += len;
- s->connected = 1;
- }
- else
- {
- s->set_eof();
- }
-}
-
-static
-void send_from_fifo(Session *s)
-{
- ssize_t len = s->fd.write(&s->wdata[0], s->wdata_size);
-
- if (len > 0)
- {
- s->wdata_size -= len;
- if (s->wdata_size)
- {
- really_memmove(&s->wdata[0], &s->wdata[len],
- s->wdata_size);
- }
- s->connected = 1;
- }
- else
- {
- s->set_eof();
- }
-}
-
-static
-void nothing_delete(Session *s)
-{
- (void)s;
-}
-
-static
-void connect_client(Session *ls)
-{
- struct sockaddr_in client_address;
- socklen_t len = sizeof(client_address);
-
- io::FD fd = ls->fd.accept(reinterpret_cast<struct sockaddr *>(&client_address), &len);
- if (fd == io::FD())
- {
- perror("accept");
- return;
- }
- if (fd.uncast_dammit() >= SOFT_LIMIT)
- {
- FPRINTF(stderr, "softlimit reached, disconnecting : %d\n", fd.uncast_dammit());
- fd.shutdown(SHUT_RDWR);
- fd.close();
- return;
- }
- if (fd_max <= fd.uncast_dammit())
- {
- fd_max = fd.uncast_dammit() + 1;
- }
-
- const int yes = 1;
- /// Allow to bind() again after the server restarts.
- // Since the socket is still in the TIME_WAIT, there's a possibility
- // that formerly lost packets might be delivered and confuse the server.
- fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
- /// Send packets as soon as possible
- /// even if the kernel thinks there is too little for it to be worth it!
- /// Testing shows this is indeed a good idea.
- fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes);
-
- // Linux-ism: Set socket options to optimize for thin streams
- // See http://lwn.net/Articles/308919/ and
- // Documentation/networking/tcp-thin.txt .. Kernel 3.2+
-#ifdef TCP_THIN_LINEAR_TIMEOUTS
- fd.setsockopt(IPPROTO_TCP, TCP_THIN_LINEAR_TIMEOUTS, &yes, sizeof yes);
-#endif
-#ifdef TCP_THIN_DUPACK
- fd.setsockopt(IPPROTO_TCP, TCP_THIN_DUPACK, &yes, sizeof yes);
-#endif
-
- readfds.set(fd);
-
- fd.fcntl(F_SETFL, O_NONBLOCK);
-
- set_session(fd, make_unique<Session>(
- SessionIO{func_recv: recv_to_fifo, func_send: send_from_fifo},
- ls->for_inferior));
- Session *s = get_session(fd);
- s->fd = fd;
- s->rdata.new_(RFIFO_SIZE);
- s->wdata.new_(WFIFO_SIZE);
- s->max_rdata = RFIFO_SIZE;
- s->max_wdata = WFIFO_SIZE;
- s->client_ip = IP4Address(client_address.sin_addr);
- s->created = TimeT::now();
- s->connected = 0;
-}
-
-Session *make_listen_port(uint16_t port, SessionParsers inferior)
-{
- struct sockaddr_in server_address;
- io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0);
- if (fd == io::FD())
- {
- perror("socket");
- return nullptr;
- }
- if (fd_max <= fd.uncast_dammit())
- fd_max = fd.uncast_dammit() + 1;
-
- fd.fcntl(F_SETFL, O_NONBLOCK);
-
- const int yes = 1;
- /// Allow to bind() again after the server restarts.
- // Since the socket is still in the TIME_WAIT, there's a possibility
- // that formerly lost packets might be delivered and confuse the server.
- fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
- /// Send packets as soon as possible
- /// even if the kernel thinks there is too little for it to be worth it!
- // I'm not convinced this is a good idea; although in minimizes the
- // latency for an individual write, it increases traffic in general.
- fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes);
-
- server_address.sin_family = AF_INET;
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 8
-# pragma GCC diagnostic ignored "-Wuseless-cast"
-#endif
- server_address.sin_addr.s_addr = htonl(INADDR_ANY);
- server_address.sin_port = htons(port);
-#pragma GCC diagnostic pop
-
- if (fd.bind(reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(server_address)) == -1)
- {
- perror("bind");
- exit(1);
- }
- if (fd.listen(5) == -1)
- { /* error */
- perror("listen");
- exit(1);
- }
-
- readfds.set(fd);
-
- set_session(fd, make_unique<Session>(
- SessionIO{func_recv: connect_client, func_send: nullptr},
- SessionParsers{func_parse: nullptr, func_delete: nothing_delete}));
- Session *s = get_session(fd);
- s->for_inferior = inferior;
- s->fd = fd;
-
- s->created = TimeT::now();
- s->connected = 1;
-
- return s;
-}
-
-Session *make_connection(IP4Address ip, uint16_t port, SessionParsers parsers)
-{
- struct sockaddr_in server_address;
- io::FD fd = io::FD::socket(AF_INET, SOCK_STREAM, 0);
- if (fd == io::FD())
- {
- perror("socket");
- return nullptr;
- }
- if (fd_max <= fd.uncast_dammit())
- fd_max = fd.uncast_dammit() + 1;
-
- const int yes = 1;
- /// Allow to bind() again after the server restarts.
- // Since the socket is still in the TIME_WAIT, there's a possibility
- // that formerly lost packets might be delivered and confuse the server.
- fd.setsockopt(SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes);
- /// Send packets as soon as possible
- /// even if the kernel thinks there is too little for it to be worth it!
- // I'm not convinced this is a good idea; although in minimizes the
- // latency for an individual write, it increases traffic in general.
- fd.setsockopt(IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes);
-
- server_address.sin_family = AF_INET;
- server_address.sin_addr = in_addr(ip);
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wold-style-cast"
-#if __GNUC__ > 4 || __GNUC_MINOR__ >= 8
-# pragma GCC diagnostic ignored "-Wuseless-cast"
-#endif
- server_address.sin_port = htons(port);
-#pragma GCC diagnostic pop
-
- fd.fcntl(F_SETFL, O_NONBLOCK);
-
- /// Errors not caught - we must not block
- /// Let the main select() loop detect when we know the state
- fd.connect(reinterpret_cast<struct sockaddr *>(&server_address),
- sizeof(struct sockaddr_in));
-
- readfds.set(fd);
-
- set_session(fd, make_unique<Session>(
- SessionIO{func_recv: recv_to_fifo, func_send: send_from_fifo},
- parsers));
- Session *s = get_session(fd);
- s->fd = fd;
- s->rdata.new_(RFIFO_SIZE);
- s->wdata.new_(WFIFO_SIZE);
-
- s->max_rdata = RFIFO_SIZE;
- s->max_wdata = WFIFO_SIZE;
- s->created = TimeT::now();
- s->connected = 1;
-
- return s;
-}
-
-void delete_session(Session *s)
-{
- if (!s)
- return;
- // this needs to be before the fd_max--
- s->func_delete(s);
-
- io::FD fd = s->fd;
- // If this was the highest fd, decrease it
- // We could add a loop to decrement fd_max further for every null session,
- // but this is cheap and good enough for the typical case
- if (fd.uncast_dammit() == fd_max - 1)
- fd_max--;
- readfds.clr(fd);
- {
- s->rdata.delete_();
- s->wdata.delete_();
- s->session_data.reset();
- reset_session(fd);
- }
-
- // just close() would try to keep sending buffers
- fd.shutdown(SHUT_RDWR);
- fd.close();
-}
-
-void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size)
-{
- if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size)
- {
- s->rdata.resize(rfifo_size);
- s->max_rdata = rfifo_size;
- }
- if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size)
- {
- s->wdata.resize(wfifo_size);
- s->max_wdata = wfifo_size;
- }
-}
-
-void WFIFOSET(Session *s, size_t len)
-{
- if (s->wdata_size + len + 16384 > s->max_wdata)
- {
- realloc_fifo(s, s->max_rdata, s->max_wdata << 1);
- PRINTF("socket: %d wdata expanded to %zu bytes.\n", s, s->max_wdata);
- }
- if (s->wdata_size + len + 2048 < s->max_wdata)
- s->wdata_size += len;
- else
- FPRINTF(stderr, "socket: %d wdata lost !!\n", s), abort();
-}
-
-void do_sendrecv(interval_t next_ms)
-{
- bool any = false;
- io::FD_Set rfd = readfds, wfd;
- for (io::FD i : iter_fds())
- {
- Session *s = get_session(i);
- if (s)
- {
- any = true;
- if (s->wdata_size)
- wfd.set(i);
- }
- }
- if (!any)
- {
- if (!has_timers())
- {
- PRINTF("Shutting down - nothing to do\n");
- runflag = false;
- }
- return;
- }
- struct timeval timeout;
- {
- std::chrono::seconds next_s = std::chrono::duration_cast<std::chrono::seconds>(next_ms);
- std::chrono::microseconds next_us = next_ms - next_s;
- timeout.tv_sec = next_s.count();
- timeout.tv_usec = next_us.count();
- }
- if (io::FD_Set::select(fd_max, &rfd, &wfd, NULL, &timeout) <= 0)
- return;
- for (io::FD i : iter_fds())
- {
- Session *s = get_session(i);
- if (!s)
- continue;
- if (wfd.isset(i) && !s->eof)
- {
- if (s->func_send)
- //send_from_fifo(i);
- s->func_send(s);
- }
- if (rfd.isset(i) && !s->eof)
- {
- if (s->func_recv)
- //recv_to_fifo(i);
- //or connect_client(i);
- s->func_recv(s);
- }
- }
-}
-
-void do_parsepacket(void)
-{
- for (io::FD i : iter_fds())
- {
- Session *s = get_session(i);
- if (!s)
- continue;
- if (!s->connected
- && static_cast<time_t>(TimeT::now()) - static_cast<time_t>(s->created) > CONNECT_TIMEOUT)
- {
- PRINTF("Session #%d timed out\n", s);
- s->set_eof();
- }
- if (s->rdata_size && !s->eof && s->func_parse)
- {
- s->func_parse(s);
- /// some func_parse may call delete_session
- // (that's kind of evil)
- s = get_session(i);
- if (!s)
- continue;
- }
- if (s->eof)
- {
- delete_session(s);
- continue;
- }
- /// Reclaim buffer space for what was read
- RFIFOFLUSH(s);
- }
-}
-
-void RFIFOSKIP(Session *s, size_t len)
-{
- s->rdata_pos += len;
-
- if (s->rdata_size < s->rdata_pos)
- {
- FPRINTF(stderr, "too many skip\n");
- abort();
- }
-}
diff --git a/src/mmo/socket.hpp b/src/mmo/socket.hpp
deleted file mode 100644
index c166794..0000000
--- a/src/mmo/socket.hpp
+++ /dev/null
@@ -1,424 +0,0 @@
-#ifndef TMWA_MMO_SOCKET_HPP
-#define TMWA_MMO_SOCKET_HPP
-// socket.hpp - Network event system.
-//
-// Copyright © ????-2004 Athena Dev Teams
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# include "../sanity.hpp"
-
-# include <netinet/in.h>
-
-# include <cstdio>
-
-# include <array>
-
-# include "../compat/rawmem.hpp"
-
-# include "../strings/astring.hpp"
-# include "../strings/vstring.hpp"
-# include "../strings/xstring.hpp"
-
-# include "../io/fd.hpp"
-
-# include "dumb_ptr.hpp"
-# include "ip.hpp"
-# include "utils.hpp"
-# include "timer.t.hpp"
-
-struct SessionData
-{
-};
-struct SessionDeleter
-{
- // defined per-server
- void operator()(SessionData *sd);
-};
-
-struct Session;
-struct SessionIO
-{
- void (*func_recv)(Session *);
- void (*func_send)(Session *);
-};
-
-struct SessionParsers
-{
- void (*func_parse)(Session *);
- void (*func_delete)(Session *);
-};
-
-struct Session
-{
- Session(SessionIO, SessionParsers);
- Session(Session&&) = delete;
- Session& operator = (Session&&) = delete;
-
- void set_io(SessionIO);
- void set_parsers(SessionParsers);
-
- /// Checks whether a newly-connected socket actually does anything
- TimeT created;
- bool connected;
-
-private:
- /// Flag needed since structure must be freed in a server-dependent manner
- bool eof;
-public:
- void set_eof() { eof = true; }
-
- /// Currently used by clif_setwaitclose
- Timer timed_close;
-
- /// Since this is a single-threaded application, it can't block
- /// These are the read/write queues
- dumb_ptr<uint8_t[]> rdata, wdata;
- size_t max_rdata, max_wdata;
- /// How much is actually in the queue
- size_t rdata_size, wdata_size;
- /// How much has already been read from the queue
- /// Note that there is no need for a wdata_pos
- size_t rdata_pos;
-
- IP4Address client_ip;
-
-private:
- /// Send or recieve
- /// Only called when select() indicates the socket is ready
- /// If, after that, nothing is read, it sets eof
- // These could probably be hard-coded with a little work
- void (*func_recv)(Session *);
- void (*func_send)(Session *);
- /// This is the important one
- /// Set to different functions depending on whether the connection
- /// is a player or a server/ladmin
- void (*func_parse)(Session *);
- /// Cleanup function since we're not fully RAII yet
- void (*func_delete)(Session *);
-
-public:
- // this really ought to be part of session_data, once that gets sane
- SessionParsers for_inferior;
-
- /// Server-specific data type
- // (this really should include the deleter, but ...)
- std::unique_ptr<SessionData, SessionDeleter> session_data;
-
- io::FD fd;
-
- friend void do_sendrecv(interval_t next);
- friend void do_parsepacket(void);
- friend void delete_session(Session *);
-};
-
-inline
-int convert_for_printf(Session *s)
-{
- return s->fd.uncast_dammit();
-}
-
-// save file descriptors for important stuff
-constexpr int SOFT_LIMIT = FD_SETSIZE - 50;
-
-// socket timeout to establish a full connection in seconds
-constexpr int CONNECT_TIMEOUT = 15;
-
-
-void set_session(io::FD fd, std::unique_ptr<Session> sess);
-Session *get_session(io::FD fd);
-void reset_session(io::FD fd);
-int get_fd_max();
-
-class IncrFD
-{
-public:
- static
- io::FD inced(io::FD v)
- {
- return io::FD::cast_dammit(v.uncast_dammit() + 1);
- }
-};
-IteratorPair<ValueIterator<io::FD, IncrFD>> iter_fds();
-
-
-/// open a socket, bind, and listen. Return an fd, or -1 if socket() fails,
-/// but exit if bind() or listen() fails
-Session *make_listen_port(uint16_t port, SessionParsers inferior);
-/// Connect to an address, return a connected socket or -1
-// FIXME - this is IPv4 only!
-Session *make_connection(IP4Address ip, uint16_t port, SessionParsers);
-/// free() the structure and close() the fd
-void delete_session(Session *);
-/// Make a the internal queues bigger
-void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size);
-/// Update all sockets that can be read/written from the queues
-void do_sendrecv(interval_t next);
-/// Call the parser function for every socket that has read data
-void do_parsepacket(void);
-
-template<class T>
-uint8_t *pod_addressof_m(T& structure)
-{
- static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs");
- return &reinterpret_cast<uint8_t&>(structure);
-}
-
-template<class T>
-const uint8_t *pod_addressof_c(const T& structure)
-{
- static_assert(is_trivially_copyable<T>::value, "Can only byte-copy POD-ish structs");
- return &reinterpret_cast<const uint8_t&>(structure);
-}
-
-
-/// Check how much can be read
-inline
-size_t RFIFOREST(Session *s)
-{
- return s->rdata_size - s->rdata_pos;
-}
-/// Read from the queue
-inline
-const void *RFIFOP(Session *s, size_t pos)
-{
- return &s->rdata[s->rdata_pos + pos];
-}
-inline
-uint8_t RFIFOB(Session *s, size_t pos)
-{
- return *static_cast<const uint8_t *>(RFIFOP(s, pos));
-}
-inline
-uint16_t RFIFOW(Session *s, size_t pos)
-{
- return *static_cast<const uint16_t *>(RFIFOP(s, pos));
-}
-inline
-uint32_t RFIFOL(Session *s, size_t pos)
-{
- return *static_cast<const uint32_t *>(RFIFOP(s, pos));
-}
-template<class T>
-void RFIFO_STRUCT(Session *s, size_t pos, T& structure)
-{
- really_memcpy(pod_addressof_m(structure), static_cast<const uint8_t *>(RFIFOP(s, pos)), sizeof(T));
-}
-inline
-IP4Address RFIFOIP(Session *s, size_t pos)
-{
- IP4Address o;
- RFIFO_STRUCT(s, pos, o);
- return o;
-}
-template<uint8_t len>
-inline
-VString<len-1> RFIFO_STRING(Session *s, size_t pos)
-{
- const char *const begin = static_cast<const char *>(RFIFOP(s, pos));
- const char *const end = begin + len-1;
- const char *const mid = std::find(begin, end, '\0');
- return XString(begin, mid, nullptr);
-}
-inline
-AString RFIFO_STRING(Session *s, size_t pos, size_t len)
-{
- const char *const begin = static_cast<const char *>(RFIFOP(s, pos));
- const char *const end = begin + len;
- const char *const mid = std::find(begin, end, '\0');
- return XString(begin, mid, nullptr);
-}
-inline
-void RFIFO_BUF_CLONE(Session *s, uint8_t *buf, size_t len)
-{
- really_memcpy(buf, static_cast<const uint8_t *>(RFIFOP(s, 0)), len);
-}
-
-/// Done reading
-void RFIFOSKIP(Session *s, size_t len);
-
-/// Read from an arbitrary buffer
-inline
-const void *RBUFP(const uint8_t *p, size_t pos)
-{
- return p + pos;
-}
-inline
-uint8_t RBUFB(const uint8_t *p, size_t pos)
-{
- return *static_cast<const uint8_t *>(RBUFP(p, pos));
-}
-inline
-uint16_t RBUFW(const uint8_t *p, size_t pos)
-{
- return *static_cast<const uint16_t *>(RBUFP(p, pos));
-}
-inline
-uint32_t RBUFL(const uint8_t *p, size_t pos)
-{
- return *static_cast<const uint32_t *>(RBUFP(p, pos));
-}
-template<class T>
-void RBUF_STRUCT(const uint8_t *p, size_t pos, T& structure)
-{
- really_memcpy(pod_addressof_m(structure), p + pos, sizeof(T));
-}
-inline
-IP4Address RBUFIP(const uint8_t *p, size_t pos)
-{
- IP4Address o;
- RBUF_STRUCT(p, pos, o);
- return o;
-}
-template<uint8_t len>
-inline
-VString<len-1> RBUF_STRING(const uint8_t *p, size_t pos)
-{
- const char *const begin = static_cast<const char *>(RBUFP(p, pos));
- const char *const end = begin + len-1;
- const char *const mid = std::find(begin, end, '\0');
- return XString(begin, mid, nullptr);
-}
-inline
-AString RBUF_STRING(const uint8_t *p, size_t pos, size_t len)
-{
- const char *const begin = static_cast<const char *>(RBUFP(p, pos));
- const char *const end = begin + len;
- const char *const mid = std::find(begin, end, '\0');
- return XString(begin, mid, nullptr);
-}
-
-
-/// Unused - check how much data can be written
-// the existence of this seems scary
-inline
-size_t WFIFOSPACE(Session *s)
-{
- return s->max_wdata - s->wdata_size;
-}
-/// Write to the queue
-inline
-void *WFIFOP(Session *s, size_t pos)
-{
- return &s->wdata[s->wdata_size + pos];
-}
-inline
-uint8_t& WFIFOB(Session *s, size_t pos)
-{
- return *static_cast<uint8_t *>(WFIFOP(s, pos));
-}
-inline
-uint16_t& WFIFOW(Session *s, size_t pos)
-{
- return *static_cast<uint16_t *>(WFIFOP(s, pos));
-}
-inline
-uint32_t& WFIFOL(Session *s, size_t pos)
-{
- return *static_cast<uint32_t *>(WFIFOP(s, pos));
-}
-template<class T>
-void WFIFO_STRUCT(Session *s, size_t pos, T& structure)
-{
- really_memcpy(static_cast<uint8_t *>(WFIFOP(s, pos)), pod_addressof_c(structure), sizeof(T));
-}
-inline
-IP4Address& WFIFOIP(Session *s, size_t pos)
-{
- static_assert(is_trivially_copyable<IP4Address>::value, "That was the whole point");
- return *static_cast<IP4Address *>(WFIFOP(s, pos));
-}
-inline
-void WFIFO_STRING(Session *s, size_t pos, XString str, size_t len)
-{
- char *const begin = static_cast<char *>(WFIFOP(s, pos));
- char *const end = begin + len;
- char *const mid = std::copy(str.begin(), str.end(), begin);
- std::fill(mid, end, '\0');
-}
-inline
-void WFIFO_ZERO(Session *s, size_t pos, size_t len)
-{
- uint8_t *b = static_cast<uint8_t *>(WFIFOP(s, pos));
- uint8_t *e = b + len;
- std::fill(b, e, '\0');
-}
-inline
-void WFIFO_BUF_CLONE(Session *s, const uint8_t *buf, size_t len)
-{
- really_memcpy(static_cast<uint8_t *>(WFIFOP(s, 0)), buf, len);
-}
-
-/// Finish writing
-void WFIFOSET(Session *s, size_t len);
-
-/// Write to an arbitrary buffer
-inline
-void *WBUFP(uint8_t *p, size_t pos)
-{
- return p + pos;
-}
-inline
-uint8_t& WBUFB(uint8_t *p, size_t pos)
-{
- return *static_cast<uint8_t *>(WBUFP(p, pos));
-}
-inline
-uint16_t& WBUFW(uint8_t *p, size_t pos)
-{
- return *static_cast<uint16_t *>(WBUFP(p, pos));
-}
-inline
-uint32_t& WBUFL(uint8_t *p, size_t pos)
-{
- return *static_cast<uint32_t *>(WBUFP(p, pos));
-}
-template<class T>
-void WBUF_STRUCT(uint8_t *p, size_t pos, T& structure)
-{
- really_memcpy(p + pos, pod_addressof_c(structure), sizeof(T));
-}
-inline
-IP4Address& WBUFIP(uint8_t *p, size_t pos)
-{
- return *static_cast<IP4Address *>(WBUFP(p, pos));
-}
-inline
-void WBUF_STRING(uint8_t *p, size_t pos, XString s, size_t len)
-{
- char *const begin = static_cast<char *>(WBUFP(p, pos));
- char *const end = begin + len;
- char *const mid = std::copy(s.begin(), s.end(), begin);
- std::fill(mid, end, '\0');
-}
-inline
-void WBUF_ZERO(uint8_t *p, size_t pos, size_t len)
-{
- uint8_t *b = static_cast<uint8_t *>(WBUFP(p, pos));
- uint8_t *e = b + len;
- std::fill(b, e, '\0');
-}
-
-inline
-void RFIFO_WFIFO_CLONE(Session *rs, Session *ws, size_t len)
-{
- really_memcpy(static_cast<uint8_t *>(WFIFOP(ws, 0)),
- static_cast<const uint8_t *>(RFIFOP(rs, 0)), len);
-}
-
-#endif // TMWA_MMO_SOCKET_HPP
diff --git a/src/mmo/dumb_ptr.cpp b/src/mmo/strs.cpp
index 77e3080..71dceec 100644
--- a/src/mmo/dumb_ptr.cpp
+++ b/src/mmo/strs.cpp
@@ -1,7 +1,7 @@
-#include "dumb_ptr.hpp"
-// dumb_ptr.cpp - dummy file to make Make dependencies work
+#include "strs.hpp"
+// strs.cpp - common string types
//
-// Copyright © 2013 Ben Longbons <b.r.longbons@gmail.com>
+// Copyright © 2014 Ben Longbons <b.r.longbons@gmail.com>
//
// This file is part of The Mana World (Athena server)
//
@@ -19,3 +19,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "../poison.hpp"
+
+
+namespace tmwa
+{
+} // namespace tmwa
diff --git a/src/mmo/strs.hpp b/src/mmo/strs.hpp
new file mode 100644
index 0000000..fea0c98
--- /dev/null
+++ b/src/mmo/strs.hpp
@@ -0,0 +1,126 @@
+#pragma once
+// strs.hpp - common string types
+//
+// Copyright © ????-2004 Athena Dev Teams
+// Copyright © 2004-2011 The Mana World Development Team
+// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
+//
+// This file is part of The Mana World (Athena server)
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+#include "fwd.hpp"
+
+#include "../strings/vstring.hpp"
+
+
+namespace tmwa
+{
+// affects CharName
+#define NAME_IGNORING_CASE 1
+
+struct AccountName : VString<23> {};
+struct AccountPass : VString<23> {};
+struct AccountCrypt : VString<39> {};
+struct AccountEmail : VString<39> {};
+struct ServerName : VString<19> {};
+struct PartyName : VString<23> {};
+struct VarName : VString<31> {};
+
+#define DEFAULT_EMAIL stringish<AccountEmail>("a@a.com"_s)
+
+// It is decreed: a mapname shall not contain an extension
+class MapName : public strings::_crtp_string<MapName, MapName, strings::ZPair>
+{
+ VString<15> _impl;
+public:
+ MapName() = default;
+ MapName(VString<15> v) : _impl(v.xislice_h(std::find(v.begin(), v.end(), '.'))) {}
+
+ iterator begin() const { return &*_impl.begin(); }
+ iterator end() const { return &*_impl.end(); }
+ const char *c_str() const { return _impl.c_str(); }
+
+ operator RString() const { return _impl; }
+ operator AString() const { return _impl; }
+ operator TString() const { return _impl; }
+ operator SString() const { return _impl; }
+ operator ZString() const { return _impl; }
+ operator XString() const { return _impl; }
+};
+template<>
+inline
+MapName stringish<MapName>(VString<15> iv)
+{
+ return iv;
+}
+inline
+const char *decay_for_printf(const MapName& vs) { return vs.c_str(); }
+
+// It is decreed: a charname is sometimes case sensitive
+struct CharName
+{
+private:
+ VString<23> _impl;
+public:
+ CharName() = default;
+ explicit CharName(VString<23> name)
+ : _impl(name)
+ {}
+
+ VString<23> to__actual() const
+ {
+ return _impl;
+ }
+ VString<23> to__lower() const
+ {
+ return _impl.to_lower();
+ }
+ VString<23> to__upper() const
+ {
+ return _impl.to_upper();
+ }
+ VString<23> to__canonical() const
+ {
+#if NAME_IGNORING_CASE == 0
+ return to__actual();
+#endif
+#if NAME_IGNORING_CASE == 1
+ return to__lower();
+#endif
+ }
+
+ friend bool operator == (const CharName& l, const CharName& r)
+ { return l.to__canonical() == r.to__canonical(); }
+ friend bool operator != (const CharName& l, const CharName& r)
+ { return l.to__canonical() != r.to__canonical(); }
+ friend bool operator < (const CharName& l, const CharName& r)
+ { return l.to__canonical() < r.to__canonical(); }
+ friend bool operator <= (const CharName& l, const CharName& r)
+ { return l.to__canonical() <= r.to__canonical(); }
+ friend bool operator > (const CharName& l, const CharName& r)
+ { return l.to__canonical() > r.to__canonical(); }
+ friend bool operator >= (const CharName& l, const CharName& r)
+ { return l.to__canonical() >= r.to__canonical(); }
+
+ friend
+ VString<23> convert_for_printf(const CharName& vs) { return vs.to__actual(); }
+};
+template<>
+inline
+CharName stringish<CharName>(VString<23> iv)
+{
+ return CharName(iv);
+}
+} // namespace tmwa
diff --git a/src/mmo/timer.cpp b/src/mmo/timer.cpp
deleted file mode 100644
index 6e28a12..0000000
--- a/src/mmo/timer.cpp
+++ /dev/null
@@ -1,221 +0,0 @@
-#include "timer.hpp"
-// timer.cpp - Future event scheduler.
-//
-// Copyright © ????-2004 Athena Dev Teams
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-#include <sys/stat.h>
-#include <sys/time.h>
-
-#include <cassert>
-#include <cstring>
-
-#include <queue>
-
-#include "../strings/zstring.hpp"
-
-#include "../io/cxxstdio.hpp"
-
-#include "utils.hpp"
-
-#include "../poison.hpp"
-
-struct TimerData
-{
- /// This will be reset on call, to avoid problems.
- Timer *owner;
-
- /// When it will be triggered
- tick_t tick;
- /// What will be done
- timer_func func;
- /// Repeat rate - 0 for oneshot
- interval_t interval;
-
- TimerData(Timer *o, tick_t t, timer_func f, interval_t i)
- : owner(o)
- , tick(t)
- , func(std::move(f))
- , interval(i)
- {}
-};
-
-struct TimerCompare
-{
- /// implement "less than"
- bool operator() (dumb_ptr<TimerData> l, dumb_ptr<TimerData> r)
- {
- // C++ provides a max-heap, but we want
- // the smallest tick to be the head (a min-heap).
- return l->tick > r->tick;
- }
-};
-
-static
-std::priority_queue<dumb_ptr<TimerData>, std::vector<dumb_ptr<TimerData>>, TimerCompare> timer_heap;
-
-
-tick_t gettick_cache;
-
-tick_t milli_clock::now(void) noexcept
-{
- struct timeval tval;
- // BUG: This will cause strange behavior if the system clock is changed!
- // it should be reimplemented in terms of clock_gettime(CLOCK_MONOTONIC, )
- gettimeofday(&tval, NULL);
- return gettick_cache = tick_t(std::chrono::seconds(tval.tv_sec)
- + std::chrono::duration_cast<std::chrono::milliseconds>(
- std::chrono::microseconds(tval.tv_usec)));
-}
-
-static
-void do_nothing(TimerData *, tick_t)
-{
-}
-
-void Timer::cancel()
-{
- if (!td)
- return;
-
- assert (this == td->owner);
- td->owner = nullptr;
- td->func = do_nothing;
- td->interval = interval_t::zero();
- td = nullptr;
-}
-
-void Timer::detach()
-{
- assert (this == td->owner);
- td->owner = nullptr;
- td = nullptr;
-}
-
-static
-void push_timer_heap(dumb_ptr<TimerData> td)
-{
- timer_heap.push(td);
-}
-
-static
-dumb_ptr<TimerData> top_timer_heap(void)
-{
- if (timer_heap.empty())
- return dumb_ptr<TimerData>();
- return timer_heap.top();
-}
-
-static
-void pop_timer_heap(void)
-{
- timer_heap.pop();
-}
-
-Timer::Timer(tick_t tick, timer_func func, interval_t interval)
-: td(dumb_ptr<TimerData>::make(this, tick, std::move(func), interval))
-{
- assert (interval >= interval_t::zero());
-
- push_timer_heap(td);
-}
-
-Timer::Timer(Timer&& t)
-: td(t.td)
-{
- t.td = nullptr;
- if (td)
- {
- assert (td->owner == &t);
- td->owner = this;
- }
-}
-
-Timer& Timer::operator = (Timer&& t)
-{
- std::swap(td, t.td);
- if (td)
- {
- assert (td->owner == &t);
- td->owner = this;
- }
- if (t.td)
- {
- assert (t.td->owner == this);
- t.td->owner = &t;
- }
- return *this;
-}
-
-interval_t do_timer(tick_t tick)
-{
- /// Number of milliseconds until it calls this again
- // this says to wait 1 sec if all timers get popped
- interval_t nextmin = std::chrono::seconds(1);
-
- while (dumb_ptr<TimerData> td = top_timer_heap())
- {
- // while the heap is not empty and
- if (td->tick > tick)
- {
- /// Return the time until the next timer needs to goes off
- nextmin = td->tick - tick;
- break;
- }
- pop_timer_heap();
-
- // Prevent destroying the object we're in.
- // Note: this would be surprising in an interval timer,
- // but all interval timers do an immediate explicit detach().
- if (td->owner)
- td->owner->detach();
- // If we are too far past the requested tick, call with
- // the current tick instead to fix reregistration problems
- if (td->tick + std::chrono::seconds(1) < tick)
- td->func(td.operator->(), tick);
- else
- td->func(td.operator->(), td->tick);
-
- if (td->interval == interval_t::zero())
- {
- td.delete_();
- continue;
- }
- if (td->tick + std::chrono::seconds(1) < tick)
- td->tick = tick + td->interval;
- else
- td->tick += td->interval;
- push_timer_heap(td);
- }
-
- return std::max(nextmin, std::chrono::milliseconds(10));
-}
-
-tick_t file_modified(ZString name)
-{
- struct stat buf;
- if (stat(name.c_str(), &buf))
- return tick_t();
- return tick_t(std::chrono::seconds(buf.st_mtime));
-}
-
-bool has_timers()
-{
- return !timer_heap.empty();
-}
diff --git a/src/mmo/timer.hpp b/src/mmo/timer.hpp
deleted file mode 100644
index 363cf17..0000000
--- a/src/mmo/timer.hpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef TMWA_MMO_TIMER_HPP
-#define TMWA_MMO_TIMER_HPP
-// timer.hpp - Future event scheduler.
-//
-// Copyright © ????-2004 Athena Dev Teams
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# include "timer.t.hpp"
-
-# include "../sanity.hpp"
-
-# include "../strings/fwd.hpp"
-
-// updated automatically when using milli_clock::now()
-// which is done only by core.cpp
-extern tick_t gettick_cache;
-
-inline
-tick_t gettick(void)
-{
- return gettick_cache;
-}
-
-/// Do all timers scheduled before tick, and return the number of
-/// milliseconds until the next timer happens
-interval_t do_timer(tick_t tick);
-
-/// Stat a file, and return its modification time, truncated to seconds.
-tick_t file_modified(ZString name);
-
-/// Check if there are any events at all scheduled.
-bool has_timers();
-
-#endif // TMWA_MMO_TIMER_HPP
diff --git a/src/mmo/timer.t.hpp b/src/mmo/timer.t.hpp
deleted file mode 100644
index 6066e7c..0000000
--- a/src/mmo/timer.t.hpp
+++ /dev/null
@@ -1,90 +0,0 @@
-#ifndef TMWA_MMO_TIMER_T_HPP
-#define TMWA_MMO_TIMER_T_HPP
-// timer.t.hpp - Future event scheduler.
-//
-// Copyright © ????-2004 Athena Dev Teams
-// Copyright © 2004-2011 The Mana World Development Team
-// Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
-//
-// This file is part of The Mana World (Athena server)
-//
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-# include "../sanity.hpp"
-
-# include <chrono>
-# include <functional>
-
-# include "dumb_ptr.hpp"
-
-struct TimerData;
-
-/// An implementation of the C++ "clock" concept, exposing
-/// durations in milliseconds.
-class milli_clock
-{
-public:
- typedef std::chrono::milliseconds duration;
- typedef duration::rep rep;
- typedef duration::period period;
- typedef std::chrono::time_point<milli_clock, duration> time_point;
- static const bool is_steady = true; // assumed - not necessarily true
-
- static time_point now() noexcept;
-};
-
-/// A point in time.
-typedef milli_clock::time_point tick_t;
-/// The difference between two points in time.
-typedef milli_clock::duration interval_t;
-/// (to get additional arguments, use std::bind or a lambda).
-typedef std::function<void (TimerData *, tick_t)> timer_func;
-
-class Timer
-{
- friend struct TimerData;
- dumb_ptr<TimerData> td;
-
- Timer(const Timer&) = delete;
- Timer& operator = (const Timer&) = delete;
-public:
- /// Don't own anything yet.
- Timer() = default;
- /// Schedule a timer for the given tick.
- /// If you do not wish to keep track of it, call disconnect().
- /// Otherwise, you may cancel() or replace (operator =) it later.
- ///
- /// If the interval argument is given, the timer will reschedule
- /// itself again forever. Otherwise, it will disconnect() itself
- /// just BEFORE it is called.
- Timer(tick_t tick, timer_func func, interval_t interval=interval_t::zero());
-
- Timer(Timer&& t);
- Timer& operator = (Timer&& t);
- ~Timer() { cancel(); }
-
- /// Cancel the delivery of this timer's function, and make it falsy.
- /// Implementation note: this doesn't actually remove it, just sets
- /// the functor to do_nothing, and waits for the tick before removing.
- void cancel();
- /// Make it falsy without cancelling the timer,
- void detach();
-
- /// Check if there is a timer connected.
- explicit operator bool() { return bool(td); }
- /// Check if there is no connected timer.
- bool operator !() { return !td; }
-};
-
-#endif // TMWA_MMO_TIMER_T_HPP
diff --git a/src/mmo/utils.cpp b/src/mmo/utils.cpp
index a1316d1..f8aff2e 100644
--- a/src/mmo/utils.cpp
+++ b/src/mmo/utils.cpp
@@ -20,12 +20,10 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-#include <netinet/in.h>
#include <sys/time.h>
#include <algorithm>
-#include "../strings/astring.hpp"
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
@@ -36,6 +34,9 @@
#include "../poison.hpp"
+
+namespace tmwa
+{
//---------------------------------------------------
// E-mail check: return 0 (not correct) or 1 (valid).
//---------------------------------------------------
@@ -57,9 +58,9 @@ bool e_mail_check(XString email)
return 0;
if (hostname.front() == '.' || hostname.back() == '.')
return 0;
- if (hostname.contains_seq(".."))
+ if (hostname.contains_seq(".."_s))
return 0;
- if (email.contains_any(" ;"))
+ if (email.contains_any(" ;"_s))
return 0;
return email.is_print();
}
@@ -70,18 +71,18 @@ bool e_mail_check(XString email)
//-------------------------------------------------
int config_switch(ZString str)
{
- if (str == "true" || str == "on" || str == "yes"
- || str == "oui" || str == "ja"
- || str == "si")
+ if (str == "true"_s || str == "on"_s || str == "yes"_s
+ || str == "oui"_s || str == "ja"_s
+ || str == "si"_s)
return 1;
- if (str == "false" || str == "off" || str == "no"
- || str == "non" || str == "nein")
+ if (str == "false"_s || str == "off"_s || str == "no"_s
+ || str == "non"_s || str == "nein"_s)
return 0;
int rv;
if (extract(str, &rv))
return rv;
- FPRINTF(stderr, "Fatal: bad option value %s", str);
+ FPRINTF(stderr, "Fatal: bad option value %s"_fmt, str);
abort();
}
@@ -93,17 +94,17 @@ void stamp_time(timestamp_seconds_buffer& out, const TimeT *t)
struct tm when = t ? *t : TimeT::now();
char buf[20];
strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when);
- out = stringish<timestamp_seconds_buffer>(const_(buf));
+ out = stringish<timestamp_seconds_buffer>(VString<19>(strings::really_construct_from_a_pointer, buf));
}
void stamp_time(timestamp_milliseconds_buffer& out)
{
struct timeval tv;
- gettimeofday(&tv, NULL);
+ gettimeofday(&tv, nullptr);
struct tm when = TimeT(tv.tv_sec);
char buf[24];
strftime(buf, 20, "%Y-%m-%d %H:%M:%S", &when);
sprintf(buf + 19, ".%03d", static_cast<int>(tv.tv_usec / 1000));
- out = stringish<timestamp_milliseconds_buffer>(const_(buf));
+ out = stringish<timestamp_milliseconds_buffer>(VString<23>(strings::really_construct_from_a_pointer, buf));
}
void log_with_timestamp(io::WriteFile& out, XString line)
@@ -119,3 +120,4 @@ void log_with_timestamp(io::WriteFile& out, XString line)
out.really_put(": ", 2);
out.put_line(line);
}
+} // namespace tmwa
diff --git a/src/mmo/utils.hpp b/src/mmo/utils.hpp
index d59f7ac..fc3ea74 100644
--- a/src/mmo/utils.hpp
+++ b/src/mmo/utils.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_UTILS_HPP
-#define TMWA_MMO_UTILS_HPP
+#pragma once
// utils.hpp - Useful stuff that hasn't been categorized.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,19 +20,25 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include <cstdio>
+#include <cstring>
+#include <ctime>
-# include <type_traits>
+#include <type_traits>
-# include "../strings/fwd.hpp"
-# include "../strings/vstring.hpp"
+#include "../ints/little.hpp"
-# include "../generic/operators.hpp"
+#include "../strings/fwd.hpp"
+#include "../strings/vstring.hpp"
-# include "../io/fwd.hpp"
+#include "../generic/operators.hpp"
+#include "../io/fwd.hpp"
+
+
+namespace tmwa
+{
template<class T>
struct is_trivially_copyable
: std::integral_constant<bool,
@@ -82,7 +87,7 @@ struct TimeT : Comparable
TimeT now()
{
// poisoned, but this is still in header-land
- return time(NULL);
+ return time(nullptr);
}
bool error() const
@@ -101,12 +106,40 @@ long long convert_for_printf(TimeT t)
return t.value;
}
-inline
-long long& convert_for_scanf(TimeT& t)
+// 2038 problem
+inline __attribute__((warn_unused_result))
+bool native_to_network(Little32 *net, TimeT nat)
{
- return t.value;
+ time_t tmp = nat;
+ return native_to_network(net, static_cast<uint32_t>(tmp));
+}
+
+inline __attribute__((warn_unused_result))
+bool network_to_native(TimeT *nat, Little32 net)
+{
+ uint32_t tmp;
+ bool rv = network_to_native(&tmp, net);
+ *nat = static_cast<time_t>(tmp);
+ return rv;
}
+inline __attribute__((warn_unused_result))
+bool native_to_network(Little64 *net, TimeT nat)
+{
+ time_t tmp = nat;
+ return native_to_network(net, static_cast<uint64_t>(tmp));
+}
+
+inline __attribute__((warn_unused_result))
+bool network_to_native(TimeT *nat, Little64 net)
+{
+ uint64_t tmp;
+ bool rv = network_to_native(&tmp, net);
+ *nat = static_cast<time_t>(tmp);
+ return rv;
+}
+
+
struct timestamp_seconds_buffer : VString<19> {};
struct timestamp_milliseconds_buffer : VString<23> {};
void stamp_time(timestamp_seconds_buffer&, const TimeT *t=nullptr);
@@ -115,21 +148,20 @@ void stamp_time(timestamp_milliseconds_buffer&);
void log_with_timestamp(io::WriteFile& out, XString line);
// TODO VString?
-# define TIMESTAMP_DUMMY "YYYY-MM-DD HH:MM:SS"
+#define TIMESTAMP_DUMMY "YYYY-MM-DD HH:MM:SS"
static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer),
"timestamp size");
-# define WITH_TIMESTAMP(str) str TIMESTAMP_DUMMY
+#define WITH_TIMESTAMP(str) str TIMESTAMP_DUMMY
// str: prefix: YYYY-MM-DD HH:MM:SS
// sizeof: 01234567890123456789012345678
// str + sizeof: ^
// -1: ^
// there's probably a better way to do this now
-# define REPLACE_TIMESTAMP(str, t) \
+#define REPLACE_TIMESTAMP(str, t) \
stamp_time( \
reinterpret_cast<timestamp_seconds_buffer *>( \
str + sizeof(str) \
)[-1], \
&t \
)
-
-#endif // TMWA_MMO_UTILS_HPP
+} // namespace tmwa
diff --git a/src/mmo/version.cpp b/src/mmo/version.cpp
index 54b1709..2e337c1 100644
--- a/src/mmo/version.cpp
+++ b/src/mmo/version.cpp
@@ -28,6 +28,9 @@
#include "../poison.hpp"
+
+namespace tmwa
+{
Version CURRENT_VERSION =
{
VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH,
@@ -61,7 +64,7 @@ Version CURRENT_MAP_SERVER_VERSION =
VENDOR_POINT,
};
-const char CURRENT_VERSION_STRING[] = VERSION_STRING;
+LString CURRENT_VERSION_STRING = VERSION_STRING;
bool extract(XString str, Version *vers)
{
@@ -70,3 +73,4 @@ bool extract(XString str, Version *vers)
// It would've been useful during the magic migration.
return extract(str, record<'.'>(&vers->major, &vers->minor, &vers->patch));
}
+} // namespace tmwa
diff --git a/src/mmo/version.hpp b/src/mmo/version.hpp
index 11bab39..440dce6 100644
--- a/src/mmo/version.hpp
+++ b/src/mmo/version.hpp
@@ -1,5 +1,4 @@
-#ifndef TMWA_MMO_VERSION_HPP
-#define TMWA_MMO_VERSION_HPP
+#pragma once
// version.hpp - Prevent mass rebuild when conf/version.hpp changes.
//
// Copyright © ????-2004 Athena Dev Teams
@@ -21,20 +20,24 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
-# include "../sanity.hpp"
+#include "fwd.hpp"
-# include <cstdint>
+#include <cstdint>
-# include "../strings/fwd.hpp"
+#include "../strings/fwd.hpp"
+
+namespace tmwa
+{
// TODO make these bitwise enums
-# define TMWA_FLAG_REGISTRATION 0x01
+#define TMWA_FLAG_REGISTRATION 0x01
-# define TMWA_SERVER_LOGIN 0x01
-# define TMWA_SERVER_CHAR 0x02
-# define TMWA_SERVER_INTER 0x04
-# define TMWA_SERVER_MAP 0x08
+#define TMWA_SERVER_LOGIN 0x01
+#define TMWA_SERVER_CHAR 0x02
+#define TMWA_SERVER_INTER 0x04
+#define TMWA_SERVER_MAP 0x08
+// TODO now that I generate the protocol, split 'flags' out of the struct
struct Version
{
uint8_t major;
@@ -46,6 +49,35 @@ struct Version
uint8_t which;
uint16_t vend;
// can't add vendor name yet
+
+ constexpr friend
+ bool operator < (Version l, Version r)
+ {
+ return (l.major < r.major
+ || (l.major == r.major
+ && (l.minor < r.minor
+ || (l.minor == r.minor
+ && (l.patch < r.patch
+ || (l.patch == r.patch
+ && (l.devel < r.devel
+ || (l.devel == r.devel
+ && l.vend < r.vend))))))));
+ }
+ constexpr friend
+ bool operator > (Version l, Version r)
+ {
+ return r < l;
+ }
+ constexpr friend
+ bool operator <= (Version l, Version r)
+ {
+ return !(r < l);
+ }
+ constexpr friend
+ bool operator >= (Version l, Version r)
+ {
+ return !(l < r);
+ }
};
static_assert(sizeof(Version) == 8, "this is sent over the network, can't change");
@@ -55,37 +87,7 @@ extern Version CURRENT_LOGIN_SERVER_VERSION;
extern Version CURRENT_CHAR_SERVER_VERSION;
extern Version CURRENT_MAP_SERVER_VERSION;
-extern const char CURRENT_VERSION_STRING[];
+extern LString CURRENT_VERSION_STRING;
bool extract(XString str, Version *vers);
-
-constexpr
-bool operator < (Version l, Version r)
-{
- return (l.major < r.major
- || (l.major == r.major
- && (l.minor < r.minor
- || (l.minor == r.minor
- && (l.patch < r.patch
- || (l.patch == r.patch
- && (l.devel < r.devel
- || (l.devel == r.devel
- && l.vend < r.vend))))))));
-}
-constexpr
-bool operator > (Version l, Version r)
-{
- return r < l;
-}
-constexpr
-bool operator <= (Version l, Version r)
-{
- return !(r < l);
-}
-constexpr
-bool operator >= (Version l, Version r)
-{
- return !(l < r);
-}
-
-#endif // TMWA_MMO_VERSION_HPP
+} // namespace tmwa