From 86395f53634b3ef1ce76a7f1e5edfdb61f8ffd80 Mon Sep 17 00:00:00 2001 From: Ben Longbons Date: Sat, 25 Oct 2014 15:24:26 -0700 Subject: Fix header ranking --- src/admin/fwd.hpp | 9 + src/admin/ladmin.cpp | 12 +- src/admin/main.cpp | 2 +- src/ast/fwd.hpp | 6 + src/ast/npc.cpp | 7 +- src/ast/npc.hpp | 5 +- src/char/char.cpp | 15 +- src/char/char.hpp | 4 +- src/char/fwd.hpp | 11 + src/char/int_party.cpp | 10 +- src/char/int_party.hpp | 6 - src/char/int_storage.cpp | 12 +- src/char/int_storage.hpp | 8 - src/char/inter.cpp | 9 +- src/char/inter.hpp | 4 - src/char/main.cpp | 2 +- src/compat/fwd.hpp | 5 + src/compat/operators.hpp | 68 ++++ src/compat/rawmem.hpp | 21 ++ src/compat/time_t.hpp | 84 ++++- src/generic/fwd.hpp | 4 + src/generic/md5.hpp | 1 - src/generic/operators.hpp | 68 ---- src/high/core.cpp | 161 ++++++++ src/high/core.hpp | 47 +++ src/high/extract_mmo.cpp | 95 +++++ src/high/extract_mmo.hpp | 32 ++ src/high/fwd.hpp | 39 ++ src/high/md5more.cpp | 159 ++++++++ src/high/md5more.hpp | 44 +++ src/high/mmo.hpp | 71 ++++ src/high/utils.cpp | 86 +++++ src/high/utils.hpp | 29 ++ src/ints/fwd.hpp | 2 + src/io/cxxstdio_enums.hpp | 77 ---- src/io/dir.hpp | 2 - src/io/extract.cpp | 220 +++++++++++ src/io/extract.hpp | 232 ++++++++++++ src/io/extract_test.cpp | 452 +++++++++++++++++++++++ src/io/fd.hpp | 2 - src/io/fwd.hpp | 6 + src/io/read.cpp | 2 +- src/io/read.hpp | 2 - src/io/write.hpp | 2 - src/login/fwd.hpp | 11 + src/login/login.cpp | 15 +- src/login/login.hpp | 2 - src/login/login.t.hpp | 44 --- src/login/main.cpp | 2 +- src/map/atcommand.cpp | 13 +- src/map/atcommand.hpp | 8 - src/map/battle.cpp | 4 +- src/map/battle.hpp | 8 +- src/map/chrif.cpp | 7 +- src/map/chrif.hpp | 8 - src/map/clif.cpp | 45 +-- src/map/clif.hpp | 13 +- src/map/clif.t.hpp | 717 ------------------------------------ src/map/fwd.hpp | 20 +- src/map/grfio.cpp | 5 +- src/map/grfio.hpp | 4 - src/map/intif.cpp | 5 +- src/map/intif.hpp | 10 - src/map/itemdb.cpp | 2 +- src/map/itemdb.hpp | 2 +- src/map/magic-expr.cpp | 3 +- src/map/magic-expr.hpp | 6 - src/map/magic-interpreter-base.cpp | 3 +- src/map/magic-interpreter-base.hpp | 6 - src/map/magic-interpreter.hpp | 6 +- src/map/magic-stmt.cpp | 3 +- src/map/magic-stmt.hpp | 6 +- src/map/magic.hpp | 6 +- src/map/main.cpp | 2 +- src/map/map.cpp | 14 +- src/map/map.hpp | 36 +- src/map/map.t.hpp | 7 +- src/map/mapflag.cpp | 2 + src/map/mapflag.hpp | 2 - src/map/mob.cpp | 4 +- src/map/mob.hpp | 5 +- src/map/npc-internal.hpp | 2 - src/map/npc-parse.cpp | 3 + src/map/npc-parse.hpp | 8 - src/map/npc.cpp | 4 +- src/map/npc.hpp | 6 - src/map/party.cpp | 2 +- src/map/party.hpp | 8 - src/map/path.cpp | 2 +- src/map/path.hpp | 2 - src/map/pc.cpp | 6 +- src/map/pc.hpp | 8 +- src/map/script-call.cpp | 3 +- src/map/script-call.hpp | 6 - src/map/script-fun.cpp | 5 +- src/map/script-parse-internal.hpp | 2 - src/map/script-parse.cpp | 3 +- src/map/script-parse.hpp | 4 - src/map/script-startup-internal.hpp | 4 - src/map/script-startup.cpp | 3 +- src/map/script-startup.hpp | 2 - src/map/skill-pools.cpp | 3 +- src/map/skill.cpp | 4 +- src/map/skill.hpp | 4 +- src/map/skill.t.hpp | 136 ------- src/map/storage.cpp | 2 +- src/map/storage.hpp | 8 +- src/map/tmw.cpp | 1 - src/map/tmw.hpp | 4 - src/map/trade.hpp | 4 +- src/mmo/clif.t.hpp | 717 ++++++++++++++++++++++++++++++++++++ src/mmo/config_parse.hpp | 2 - src/mmo/core.cpp | 161 -------- src/mmo/core.hpp | 49 --- src/mmo/cxxstdio_enums.hpp | 77 ++++ src/mmo/extract.cpp | 280 -------------- src/mmo/extract.hpp | 240 ------------ src/mmo/extract_enums.cpp | 59 +++ src/mmo/extract_enums.hpp | 6 +- src/mmo/extract_test.cpp | 448 ---------------------- src/mmo/fwd.hpp | 32 +- src/mmo/human_time_diff.cpp | 68 ++++ src/mmo/human_time_diff.hpp | 45 +-- src/mmo/ids.cpp | 42 +++ src/mmo/ids.hpp | 17 +- src/mmo/login.t.hpp | 44 +++ src/mmo/md5more.cpp | 159 -------- src/mmo/md5more.hpp | 48 --- src/mmo/mmo.hpp | 71 ---- src/mmo/skill.t.hpp | 136 +++++++ src/mmo/strs.hpp | 33 ++ src/mmo/utils.cpp | 123 ------- src/mmo/utils.hpp | 167 --------- src/mmo/version.cpp | 2 +- src/mmo/version.hpp | 2 - src/monitor/main.cpp | 3 +- src/net/fwd.hpp | 9 +- src/net/ip.cpp | 3 +- src/net/ip.hpp | 2 - src/net/packets.cpp | 106 ------ src/net/packets.hpp | 585 ----------------------------- src/net/socket.cpp | 16 +- src/net/socket.hpp | 19 +- src/net/timer.hpp | 3 - src/net/timestamp-utils.cpp | 72 ++++ src/net/timestamp-utils.hpp | 54 +++ src/proto-base/fwd.hpp | 5 + src/range/fwd.hpp | 2 + src/sexpr/fwd.hpp | 5 + src/sexpr/lexer.hpp | 1 - src/sexpr/parser.hpp | 2 - src/strings/astring.py | 2 +- src/strings/fwd.hpp | 2 + src/strings/rstring.py | 2 +- src/tests/fwd.hpp | 4 + src/wire/fwd.hpp | 34 ++ src/wire/packets.cpp | 106 ++++++ src/wire/packets.hpp | 582 +++++++++++++++++++++++++++++ 158 files changed, 4142 insertions(+), 3945 deletions(-) create mode 100644 src/compat/operators.hpp delete mode 100644 src/generic/operators.hpp create mode 100644 src/high/core.cpp create mode 100644 src/high/core.hpp create mode 100644 src/high/extract_mmo.cpp create mode 100644 src/high/extract_mmo.hpp create mode 100644 src/high/fwd.hpp create mode 100644 src/high/md5more.cpp create mode 100644 src/high/md5more.hpp create mode 100644 src/high/mmo.hpp create mode 100644 src/high/utils.cpp create mode 100644 src/high/utils.hpp delete mode 100644 src/io/cxxstdio_enums.hpp create mode 100644 src/io/extract.cpp create mode 100644 src/io/extract.hpp create mode 100644 src/io/extract_test.cpp delete mode 100644 src/login/login.t.hpp delete mode 100644 src/map/clif.t.hpp delete mode 100644 src/map/skill.t.hpp create mode 100644 src/mmo/clif.t.hpp delete mode 100644 src/mmo/core.cpp delete mode 100644 src/mmo/core.hpp create mode 100644 src/mmo/cxxstdio_enums.hpp delete mode 100644 src/mmo/extract.cpp delete mode 100644 src/mmo/extract.hpp create mode 100644 src/mmo/extract_enums.cpp delete mode 100644 src/mmo/extract_test.cpp create mode 100644 src/mmo/human_time_diff.cpp create mode 100644 src/mmo/ids.cpp create mode 100644 src/mmo/login.t.hpp delete mode 100644 src/mmo/md5more.cpp delete mode 100644 src/mmo/md5more.hpp delete mode 100644 src/mmo/mmo.hpp create mode 100644 src/mmo/skill.t.hpp delete mode 100644 src/mmo/utils.cpp delete mode 100644 src/mmo/utils.hpp delete mode 100644 src/net/packets.cpp delete mode 100644 src/net/packets.hpp create mode 100644 src/net/timestamp-utils.cpp create mode 100644 src/net/timestamp-utils.hpp create mode 100644 src/wire/fwd.hpp create mode 100644 src/wire/packets.cpp create mode 100644 src/wire/packets.hpp (limited to 'src') diff --git a/src/admin/fwd.hpp b/src/admin/fwd.hpp index 46674c8..a964d5f 100644 --- a/src/admin/fwd.hpp +++ b/src/admin/fwd.hpp @@ -20,6 +20,15 @@ #include "../sanity.hpp" +#include "../strings/fwd.hpp" // rank 1 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../mmo/fwd.hpp" // rank 6 +#include "../proto2/fwd.hpp" // rank 8 +#include "../high/fwd.hpp" // rank 9 +#include "../wire/fwd.hpp" // rank 9 +// admin/fwd.hpp is rank ∞ because it is an executable + namespace tmwa { diff --git a/src/admin/ladmin.cpp b/src/admin/ladmin.cpp index 9dae089..e3557dd 100644 --- a/src/admin/ladmin.cpp +++ b/src/admin/ladmin.cpp @@ -35,23 +35,27 @@ #include "../strings/vstring.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../io/tty.hpp" #include "../io/write.hpp" #include "../net/ip.hpp" -#include "../net/packets.hpp" +#include "../net/timestamp-utils.hpp" #include "../proto2/any-user.hpp" #include "../proto2/login-admin.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/core.hpp" #include "../mmo/human_time_diff.hpp" -#include "../mmo/mmo.hpp" -#include "../mmo/utils.hpp" +#include "../high/mmo.hpp" #include "../mmo/version.hpp" +#include "../high/core.hpp" +#include "../high/utils.hpp" + +#include "../wire/packets.hpp" + #include "../poison.hpp" diff --git a/src/admin/main.cpp b/src/admin/main.cpp index 1849d80..babf195 100644 --- a/src/admin/main.cpp +++ b/src/admin/main.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "../mmo/core.hpp" +#include "../high/core.hpp" #include "ladmin.hpp" diff --git a/src/ast/fwd.hpp b/src/ast/fwd.hpp index 77328c9..4ab4490 100644 --- a/src/ast/fwd.hpp +++ b/src/ast/fwd.hpp @@ -20,6 +20,12 @@ #include "../sanity.hpp" +#include "../compat/fwd.hpp" // rank 2 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../mmo/fwd.hpp" // rank 6 +#include "../high/fwd.hpp" // rank 9 +// ast/fwd.hpp is rank 10 namespace tmwa { diff --git a/src/ast/npc.cpp b/src/ast/npc.cpp index 362943c..ca518d8 100644 --- a/src/ast/npc.cpp +++ b/src/ast/npc.cpp @@ -18,11 +18,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "../compat/memory.hpp" + #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" -#include "../mmo/extract.hpp" +#include "../mmo/extract_enums.hpp" -#include "../map/clif.hpp" +#include "../high/extract_mmo.hpp" #include "../poison.hpp" diff --git a/src/ast/npc.hpp b/src/ast/npc.hpp index e39a704..648b40b 100644 --- a/src/ast/npc.hpp +++ b/src/ast/npc.hpp @@ -20,12 +20,15 @@ #include "fwd.hpp" +#include + #include "../compat/result.hpp" +#include "../mmo/clif.t.hpp" #include "../mmo/ids.hpp" #include "../mmo/strs.hpp" -#include "../map/map.hpp" +#include "../net/timer.t.hpp" #include "script.hpp" diff --git a/src/char/char.cpp b/src/char/char.cpp index 98a2178..0b166c2 100644 --- a/src/char/char.cpp +++ b/src/char/char.cpp @@ -49,13 +49,12 @@ #include "../generic/array.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/lock.hpp" #include "../io/read.hpp" #include "../io/tty.hpp" #include "../io/write.hpp" -#include "../net/packets.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" @@ -66,14 +65,18 @@ #include "../proto2/char-user.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/core.hpp" -#include "../mmo/extract.hpp" +#include "../mmo/cxxstdio_enums.hpp" #include "../mmo/extract_enums.hpp" #include "../mmo/human_time_diff.hpp" -#include "../mmo/mmo.hpp" -#include "../mmo/utils.hpp" #include "../mmo/version.hpp" +#include "../high/core.hpp" +#include "../high/extract_mmo.hpp" +#include "../high/mmo.hpp" +#include "../high/utils.hpp" + +#include "../wire/packets.hpp" + #include "inter.hpp" #include "int_party.hpp" #include "int_storage.hpp" diff --git a/src/char/char.hpp b/src/char/char.hpp index a9c786f..47d94d8 100644 --- a/src/char/char.hpp +++ b/src/char/char.hpp @@ -22,13 +22,11 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - #include "../generic/array.hpp" #include "../net/ip.hpp" -#include "../mmo/mmo.hpp" +#include "../high/mmo.hpp" namespace tmwa diff --git a/src/char/fwd.hpp b/src/char/fwd.hpp index 31cd1ba..ff2bf22 100644 --- a/src/char/fwd.hpp +++ b/src/char/fwd.hpp @@ -20,6 +20,17 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../mmo/fwd.hpp" // rank 6 +#include "../proto2/fwd.hpp" // rank 8 +#include "../high/fwd.hpp" // rank 9 +#include "../wire/fwd.hpp" // rank 9 +// char/fwd.hpp is rank ∞ because it is an executable + namespace tmwa { diff --git a/src/char/int_party.cpp b/src/char/int_party.cpp index 0ce827e..9a9dbd9 100644 --- a/src/char/int_party.cpp +++ b/src/char/int_party.cpp @@ -29,17 +29,19 @@ #include "../generic/db.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/lock.hpp" #include "../io/read.hpp" #include "../io/write.hpp" -#include "../net/packets.hpp" - #include "../proto2/char-map.hpp" -#include "../mmo/extract.hpp" #include "../mmo/ids.hpp" -#include "../mmo/mmo.hpp" + +#include "../high/extract_mmo.hpp" +#include "../high/mmo.hpp" + +#include "../wire/packets.hpp" #include "char.hpp" #include "inter.hpp" diff --git a/src/char/int_party.hpp b/src/char/int_party.hpp index f33fc0d..79b3bd4 100644 --- a/src/char/int_party.hpp +++ b/src/char/int_party.hpp @@ -22,12 +22,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../net/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/char/int_storage.cpp b/src/char/int_storage.cpp index a2b0bc7..c02f037 100644 --- a/src/char/int_storage.cpp +++ b/src/char/int_storage.cpp @@ -28,17 +28,19 @@ #include "../generic/db.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/lock.hpp" #include "../io/read.hpp" #include "../io/write.hpp" -#include "../net/packets.hpp" - #include "../proto2/char-map.hpp" -#include "../mmo/extract.hpp" -#include "../mmo/mmo.hpp" +#include "../mmo/cxxstdio_enums.hpp" + +#include "../high/extract_mmo.hpp" +#include "../high/mmo.hpp" + +#include "../wire/packets.hpp" #include "../poison.hpp" diff --git a/src/char/int_storage.hpp b/src/char/int_storage.hpp index 0a80027..c03ebff 100644 --- a/src/char/int_storage.hpp +++ b/src/char/int_storage.hpp @@ -22,14 +22,6 @@ #include "fwd.hpp" -#include "../compat/fwd.hpp" - -#include "../strings/fwd.hpp" - -#include "../net/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/char/inter.cpp b/src/char/inter.cpp index 2efcc83..03d027a 100644 --- a/src/char/inter.cpp +++ b/src/char/inter.cpp @@ -34,16 +34,17 @@ #include "../generic/db.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/lock.hpp" #include "../io/read.hpp" #include "../io/write.hpp" -#include "../net/packets.hpp" - #include "../proto2/char-map.hpp" -#include "../mmo/extract.hpp" -#include "../mmo/mmo.hpp" +#include "../high/extract_mmo.hpp" +#include "../high/mmo.hpp" + +#include "../wire/packets.hpp" #include "char.hpp" #include "int_party.hpp" diff --git a/src/char/inter.hpp b/src/char/inter.hpp index 19900f9..31d80b1 100644 --- a/src/char/inter.hpp +++ b/src/char/inter.hpp @@ -22,10 +22,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../net/fwd.hpp" - namespace tmwa { diff --git a/src/char/main.cpp b/src/char/main.cpp index 3648a74..7d6fee3 100644 --- a/src/char/main.cpp +++ b/src/char/main.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "../mmo/core.hpp" +#include "../high/core.hpp" #include "char.hpp" diff --git a/src/compat/fwd.hpp b/src/compat/fwd.hpp index c16e196..3fa0dd2 100644 --- a/src/compat/fwd.hpp +++ b/src/compat/fwd.hpp @@ -20,6 +20,10 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +// compat/fwd.hpp is rank 2 + namespace tmwa { @@ -33,5 +37,6 @@ namespace tmwa template class Borrowed; + struct TimeT; // meh, add more when I feel like it } // namespace tmwa diff --git a/src/compat/operators.hpp b/src/compat/operators.hpp new file mode 100644 index 0000000..bb05765 --- /dev/null +++ b/src/compat/operators.hpp @@ -0,0 +1,68 @@ +#pragma once +// operators.hpp - ADL helper for value wrappers. +// +// Copyright © 2013 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + + +namespace tmwa +{ +namespace _operators +{ + class Comparable {}; + + template + bool operator == (T l, T r) + { + return l.value == r.value; + } + + template + bool operator != (T l, T r) + { + return l.value != r.value; + } + + template + bool operator < (T l, T r) + { + return l.value < r.value; + } + + template + bool operator <= (T l, T r) + { + return l.value <= r.value; + } + + template + bool operator > (T l, T r) + { + return l.value > r.value; + } + + template + bool operator >= (T l, T r) + { + return l.value >= r.value; + } +} + +using _operators::Comparable; +} // namespace tmwa diff --git a/src/compat/rawmem.hpp b/src/compat/rawmem.hpp index c271a56..66af204 100644 --- a/src/compat/rawmem.hpp +++ b/src/compat/rawmem.hpp @@ -22,6 +22,8 @@ #include #include +#include + #include "fwd.hpp" @@ -49,4 +51,23 @@ void really_memset0(uint8_t *dest, size_t n) { memset(dest, '\0', n); } + +template +struct is_trivially_copyable +: std::integral_constant +{}; + +template +void really_memzero_this(T *v) +{ + static_assert(is_trivially_copyable::value, "only for mostly-pod types"); + static_assert(std::is_class::value || std::is_union::value, "Only for user-defined structures (for now)"); + memset(v, '\0', sizeof(*v)); +} +template +void really_memzero_this(T (&)[n]) = delete; } // namespace tmwa diff --git a/src/compat/time_t.hpp b/src/compat/time_t.hpp index 9e7cf25..e9c97c4 100644 --- a/src/compat/time_t.hpp +++ b/src/compat/time_t.hpp @@ -20,10 +20,90 @@ #include "fwd.hpp" -// TODO fix this ordering violation by promoting TimeT here -#include "../mmo/utils.hpp" +#include + +#include "../ints/little.hpp" + +#include "operators.hpp" namespace tmwa { +// Exists in place of time_t, to give it a predictable printf-format. +// (on x86 and amd64, time_t == long, but not on x32) +static_assert(sizeof(long long) >= sizeof(time_t), "long long >= time_t"); +struct TimeT : Comparable +{ + long long value; + + // conversion + TimeT(time_t t=0) : value(t) {} + TimeT(struct tm t) : value(timegm(&t)) {} + operator time_t() const { return value; } + operator struct tm() const { time_t v = value; return *gmtime(&v); } + + explicit operator bool() const { return value; } + bool operator !() const { return !value; } + + // prevent surprises + template + TimeT(T) = delete; + template + operator T() const = delete; + + static + TimeT now() + { + // poisoned, but this is still in header-land + return time(nullptr); + } + + bool error() const + { + return value == -1; + } + bool okay() const + { + return !error(); + } +}; + +inline +long long convert_for_printf(TimeT t) +{ + return t.value; +} + +// 2038 problem +inline __attribute__((warn_unused_result)) +bool native_to_network(Little32 *net, TimeT nat) +{ + time_t tmp = nat; + return native_to_network(net, static_cast(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(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(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(tmp); + return rv; +} } // namespace tmwa diff --git a/src/generic/fwd.hpp b/src/generic/fwd.hpp index 9c389b1..2517d62 100644 --- a/src/generic/fwd.hpp +++ b/src/generic/fwd.hpp @@ -20,6 +20,10 @@ #include "../sanity.hpp" +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +// generic/fwd.hpp is rank 3 + namespace tmwa { diff --git a/src/generic/md5.hpp b/src/generic/md5.hpp index 50bc987..2f07789 100644 --- a/src/generic/md5.hpp +++ b/src/generic/md5.hpp @@ -24,7 +24,6 @@ #include -#include "../strings/fwd.hpp" #include "../strings/vstring.hpp" diff --git a/src/generic/operators.hpp b/src/generic/operators.hpp deleted file mode 100644 index bb05765..0000000 --- a/src/generic/operators.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once -// operators.hpp - ADL helper for value wrappers. -// -// Copyright © 2013 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - - -namespace tmwa -{ -namespace _operators -{ - class Comparable {}; - - template - bool operator == (T l, T r) - { - return l.value == r.value; - } - - template - bool operator != (T l, T r) - { - return l.value != r.value; - } - - template - bool operator < (T l, T r) - { - return l.value < r.value; - } - - template - bool operator <= (T l, T r) - { - return l.value <= r.value; - } - - template - bool operator > (T l, T r) - { - return l.value > r.value; - } - - template - bool operator >= (T l, T r) - { - return l.value >= r.value; - } -} - -using _operators::Comparable; -} // namespace tmwa diff --git a/src/high/core.cpp b/src/high/core.cpp new file mode 100644 index 0000000..a45db18 --- /dev/null +++ b/src/high/core.cpp @@ -0,0 +1,161 @@ +#include "core.hpp" +// core.cpp - The main loop. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include + +#include + +#include +#include + +#include + +#include "../strings/zstring.hpp" +#include "../strings/literal.hpp" + +#include "../io/cxxstdio.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. +// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced +// Programming in the UNIX Environment_. +// +typedef void(*sigfunc)(int); +static +sigfunc compat_signal(int signo, sigfunc func) +{ + struct sigaction sact, oact; + + sact.sa_handler = func; + sigfillset(&sact.sa_mask); + sigdelset(&sact.sa_mask, SIGSEGV); + sigdelset(&sact.sa_mask, SIGBUS); + sigdelset(&sact.sa_mask, SIGTRAP); + sigdelset(&sact.sa_mask, SIGILL); + sigdelset(&sact.sa_mask, SIGFPE); + sact.sa_flags = 0; + + if (sigaction(signo, &sact, &oact) < 0) + { + DIAG_PUSH(); + DIAG_I(old_style_cast); + return SIG_ERR; + DIAG_POP(); + } + + return oact.sa_handler; +} + +volatile +bool runflag = true; + +static +void chld_proc(int) +{ + wait(nullptr); +} +static +void sig_proc(int) +{ + for (int i = 1; i < 31; ++i) + { + DIAG_PUSH(); + DIAG_I(old_style_cast); + compat_signal(i, SIG_IGN); + DIAG_POP(); + } + runflag = false; +} + +/* + Note about fatal signals: + + Under certain circumstances, + the following signals MUST not be ignored: + SIGFPE, SIGSEGV, SIGILL + Unless you use SA_SIGINFO and *carefully* check the origin, + that means they must be SIG_DFL. + */ +} // namespace tmwa + +int tmwa_main(int argc, char **argv) +{ + using namespace tmwa; + + check_paths(); + + // ZString args[argc]; is (deliberately!) not supported by clang yet + ZString *args = static_cast(alloca(argc * sizeof(ZString))); + for (int i = 0; i < argc; ++i) + args[i] = ZString(strings::really_construct_from_a_pointer, argv[i], nullptr); + do_init(Slice(args, argc)); + + if (!runflag) + { + 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. + + DIAG_PUSH(); + DIAG_I(old_style_cast); + compat_signal(SIGPIPE, SIG_IGN); + 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) + 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); + DIAG_POP(); + + atexit(term_func); + + while (runflag) + { + // TODO - if timers take a long time to run, this + // may wait too long in sendrecv + tick_t now = milli_clock::now(); + interval_t next = do_timer(now); + runflag &= do_sendrecv(next); + runflag &= do_parsepacket(); + } + + return 0; +} diff --git a/src/high/core.hpp b/src/high/core.hpp new file mode 100644 index 0000000..0ded246 --- /dev/null +++ b/src/high/core.hpp @@ -0,0 +1,47 @@ +#pragma once +// core.hpp - The main loop. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include "../range/slice.hpp" + + +namespace tmwa +{ +/// core.c contains a server-independent main() function +/// and then runs a do_sendrecv loop + +/// When this is cleared, the server exits gracefully. +extern volatile bool runflag; + +/// This is an external function defined by each server +/// This function must register stuff for the parse loop +extern int do_init(Slice); + +/// Cleanup function called whenever a signal kills us +/// or when if we manage to exit() gracefully. +extern void term_func(void); +} // namespace tmwa + +/// grumble grumble stupid intertwined includes mumble mumble +__attribute__((warn_unused_result)) +extern int tmwa_main(int argc, char **argv); diff --git a/src/high/extract_mmo.cpp b/src/high/extract_mmo.cpp new file mode 100644 index 0000000..a674656 --- /dev/null +++ b/src/high/extract_mmo.cpp @@ -0,0 +1,95 @@ +#include "extract_mmo.hpp" +// extract_mmo.cpp - a simple, hierarchical, tokenizer +// +// Copyright © 2013 Ben Longbons +// +// 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 . + +#include + +#include "../io/extract.hpp" + +#include "../mmo/extract_enums.hpp" + +#include "mmo.hpp" + +#include "../poison.hpp" + + +// TODO also pass an io::LineSpan around. +namespace tmwa +{ +bool extract(XString str, GlobalReg *var) +{ + return extract(str, + record<','>(&var->str, &var->value)); +} + +bool extract(XString str, Item *it) +{ + XString ignored; + XString corruption_hack_amount; + bool rv = extract(str, + record<',', 11>( + &ignored, + &it->nameid, + &corruption_hack_amount, + &it->equip, + &ignored, + &ignored, + &ignored, + &ignored, + &ignored, + &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; +} + +bool extract(XString str, NpcEvent *ev) +{ + XString mid; + return extract(str, record<':'>(&ev->npc, &mid, &ev->label)) && !mid; +} +} // namespace tmwa diff --git a/src/high/extract_mmo.hpp b/src/high/extract_mmo.hpp new file mode 100644 index 0000000..0c18090 --- /dev/null +++ b/src/high/extract_mmo.hpp @@ -0,0 +1,32 @@ +#pragma once +// extract_mmo.hpp - a simple, hierarchical, tokenizer +// +// Copyright © 2012-2013 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + + +namespace tmwa +{ +bool extract(XString str, GlobalReg *var); +bool extract(XString str, Item *it); +bool extract(XString str, MapName *m); +bool extract(XString str, CharName *out); + +bool extract(XString str, NpcEvent *ev); +} // namespace tmwa diff --git a/src/high/fwd.hpp b/src/high/fwd.hpp new file mode 100644 index 0000000..1a46b4b --- /dev/null +++ b/src/high/fwd.hpp @@ -0,0 +1,39 @@ +#pragma once +// high/fwd.hpp - list of type names for mmo lib +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "../sanity.hpp" + +#include "../range/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../mmo/fwd.hpp" // rank 6 +#include "../proto2/fwd.hpp" // rank 8 +// high/fwd.hpp is rank 9 + + +namespace tmwa +{ +class CharPair; +class PartyPair; +// meh, add more when I feel like it +} // namespace tmwa diff --git a/src/high/md5more.cpp b/src/high/md5more.cpp new file mode 100644 index 0000000..05149ac --- /dev/null +++ b/src/high/md5more.cpp @@ -0,0 +1,159 @@ +#include "md5more.hpp" +// md5more.cpp - Non-basic MD5 functions. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include + +#include "../compat/rawmem.hpp" + +#include "../generic/random.hpp" + +#include "../io/cxxstdio.hpp" +#include "../io/read.hpp" + +#include "../net/ip.hpp" + +#include "mmo.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +#define X block.data + +// TODO - refactor MD5 into a stream, and merge the implementations +// I once implemented an ostream that does it ... +MD5_state MD5_from_FILE(io::ReadFile& in) +{ + uint64_t total_len = 0; + + uint8_t buf[0x40]; + uint8_t block_len = 0; + + MD5_state state; + MD5_init(&state); + + MD5_block block; + + while (true) + { + size_t rv = in.get(sign_cast(buf + block_len), 0x40 - block_len); + if (!rv) + break; + total_len += 8 * rv; // in bits + block_len += rv; + if (block_len != 0x40) + continue; + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; + MD5_do_block(&state, block); + block_len = 0; + } + // no more input, just pad and append the length + buf[block_len] = 0x80; + really_memset0(buf + block_len + 1, 0x40 - block_len - 1); + if (block_len < 0x38) + { + for (int i = 0; i < 8; i++) + buf[0x38 + i] = total_len >> i * 8; + } + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; + MD5_do_block(&state, block); + if (0x38 <= block_len) + { + really_memset0(buf, 0x38); + for (int i = 0; i < 8; i++) + buf[0x38 + i] = total_len >> i * 8; + for (int i = 0; i < 0x10; i++) + X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; + MD5_do_block(&state, block); + } + return state; +} + + +// Hash a password with a salt. +// Whoever wrote this FAILS programming +AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt) +{ + char cbuf[64] {}; + + // hash the key then the salt + // buf ends up as a 64-char NUL-terminated string + md5_string tbuf, tbuf2; + MD5_to_str(MD5_from_string(key), tbuf); + MD5_to_str(MD5_from_string(salt), tbuf2); + const auto it = std::copy(tbuf.begin(), tbuf.end(), std::begin(cbuf)); + auto it2 = std::copy(tbuf2.begin(), tbuf2.end(), it); + assert(it2 == std::end(cbuf)); + + md5_string tbuf3; + MD5_to_str(MD5_from_string(XString(std::begin(cbuf), it2, nullptr)), tbuf3); + + VString<31> obuf; + + // This truncates the string, but we have to keep it like that for compatibility + SNPRINTF(obuf, 32, "!%s$%s"_fmt, salt, tbuf3); + return stringish(obuf); +} + +SaltString make_salt(void) +{ + char salt[5]; + for (int i = 0; i < 5; i++) + // 126 would probably actually be okay + salt[i] = random_::in(48, 125); + return stringish(XString(salt + 0, salt + 5, nullptr)); +} + +bool pass_ok(AccountPass password, AccountCrypt crypted) +{ + // crypted is like !salt$hash + auto begin = crypted.begin() + 1; + auto end = std::find(begin, crypted.end(), '$'); + SaltString salt = stringish(crypted.xislice(begin, end)); + + return crypted == MD5_saltcrypt(password, salt); +} + +// [M|h]ashes up an IP address and a secret key +// to return a hopefully unique masked IP. +IP4Address MD5_ip(IP4Address ip) +{ + static SaltString secret = make_salt(); + + // MD5sum a secret + the IP address + VString<31> ipbuf; + SNPRINTF(ipbuf, 32, "%s %s"_fmt, ip, secret); + md5_binary obuf; + MD5_to_bin(MD5_from_string(ipbuf), obuf); + + // Fold the md5sum to 32 bits, pack the bytes to an in_addr + return IP4Address({ + static_cast(obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]), + static_cast(obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]), + static_cast(obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]), + static_cast(obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]), + }); +} +} // namespace tmwa diff --git a/src/high/md5more.hpp b/src/high/md5more.hpp new file mode 100644 index 0000000..33ebe24 --- /dev/null +++ b/src/high/md5more.hpp @@ -0,0 +1,44 @@ +#pragma once +// md5more.hpp - Non-basic MD5 functions. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include "../generic/md5.hpp" + + +namespace tmwa +{ +MD5_state MD5_from_FILE(io::ReadFile& in); + +// whoever wrote this fails basic understanding of +AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt); + +/// return some random characters +// Currently, returns a 5-char string +SaltString make_salt(void); + +/// check plaintext password against saved saltcrypt +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); +} // namespace tmwa diff --git a/src/high/mmo.hpp b/src/high/mmo.hpp new file mode 100644 index 0000000..b5bcac8 --- /dev/null +++ b/src/high/mmo.hpp @@ -0,0 +1,71 @@ +#pragma once +// mmo.hpp - Huge mess of structures. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include "../compat/borrow.hpp" +#include "../compat/memory.hpp" + +#include "../proto2/net-CharData.hpp" +#include "../proto2/net-CharKey.hpp" +#include "../proto2/net-PartyMost.hpp" +#include "../proto2/net-SkillValue.hpp" + + +namespace tmwa +{ +inline +bool operator == (const SkillValue& l, const SkillValue& r) +{ + return l.lv == r.lv && l.flags == r.flags; +} +inline +bool operator != (const SkillValue& l, const SkillValue& r) +{ + return !(l == r); +} + +struct CharPair +{ + CharKey key; + std::unique_ptr data; + + CharPair() + : key{}, data(make_unique()) + {} +}; + +struct GM_Account +{ + AccountId account_id; + GmLevel level; +}; + +struct PartyPair +{ + PartyId party_id; + Borrowed party_most; + + PartyMost& operator *() const { return *party_most; } + Borrowed operator->() const { return party_most; } +}; +} // namespace tmwa diff --git a/src/high/utils.cpp b/src/high/utils.cpp new file mode 100644 index 0000000..9b89c31 --- /dev/null +++ b/src/high/utils.cpp @@ -0,0 +1,86 @@ +#include "utils.hpp" +// utils.cpp - Useful stuff that hasn't been categorized. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include + +#include + +#include "../strings/zstring.hpp" +#include "../strings/xstring.hpp" + +#include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +//--------------------------------------------------- +// E-mail check: return 0 (not correct) or 1 (valid). +//--------------------------------------------------- +bool e_mail_check(XString email) +{ + // athena limits + if (email.size() < 3 || email.size() > 39) + return 0; + + // part of RFC limits (official reference of e-mail description) + XString::iterator at = std::find(email.begin(), email.end(), '@'); + if (at == email.end()) + return 0; + XString username = email.xislice_h(at); + XString hostname = email.xislice_t(at + 1); + if (!username || !hostname) + return 0; + if (hostname.contains('@')) + return 0; + if (hostname.front() == '.' || hostname.back() == '.') + return 0; + if (hostname.contains_seq(".."_s)) + return 0; + if (email.contains_any(" ;"_s)) + return 0; + return email.is_print(); +} + +//------------------------------------------------- +// Return numerical value of a switch configuration +// on/off, english, français, deutsch, español +//------------------------------------------------- +int config_switch(ZString str) +{ + if (str == "true"_s || str == "on"_s || str == "yes"_s + || str == "oui"_s || str == "ja"_s + || str == "si"_s) + return 1; + 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"_fmt, str); + abort(); +} +} // namespace tmwa diff --git a/src/high/utils.hpp b/src/high/utils.hpp new file mode 100644 index 0000000..c815e03 --- /dev/null +++ b/src/high/utils.hpp @@ -0,0 +1,29 @@ +#pragma once +// utils.hpp - Useful stuff that hasn't been categorized. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +namespace tmwa +{ +bool e_mail_check(XString email); +int config_switch(ZString str); +} // namespace tmwa diff --git a/src/ints/fwd.hpp b/src/ints/fwd.hpp index a08e546..536eba1 100644 --- a/src/ints/fwd.hpp +++ b/src/ints/fwd.hpp @@ -20,6 +20,8 @@ #include "../sanity.hpp" +// ints/fwd.hpp is rank 1 + namespace tmwa { diff --git a/src/io/cxxstdio_enums.hpp b/src/io/cxxstdio_enums.hpp deleted file mode 100644 index 6f428e8..0000000 --- a/src/io/cxxstdio_enums.hpp +++ /dev/null @@ -1,77 +0,0 @@ -#pragma once -// cxxstdio_enums.hpp - Opt-in integer formatting support for enums. -// -// Copyright © 2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include - -#include "../generic/enum.hpp" - - -namespace tmwa -{ -namespace e -{ -enum class BF : uint16_t; -enum class EPOS : uint16_t; -enum class MapCell : uint8_t; -enum class Opt0 : uint16_t; - -inline -auto decay_for_printf(BF v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(EPOS v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(MapCell v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(Opt0 v) -> typename remove_enum::type { return typename remove_enum::type(v); } -} - -namespace magic -{ -enum class SPELLARG : uint8_t; - -inline -auto decay_for_printf(SPELLARG v) -> typename remove_enum::type { return typename remove_enum::type(v); } -} - -enum class BL : uint8_t; -enum class ByteCode : uint8_t; -enum class ItemLook : uint16_t; -enum class MS : uint8_t; -enum class SP : uint16_t; -enum class SkillID : uint16_t; -enum class StatusChange : uint16_t; - -inline -auto decay_for_printf(BL v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(ByteCode v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(ItemLook v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(MS v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(SP v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(SkillID v) -> typename remove_enum::type { return typename remove_enum::type(v); } -inline -auto decay_for_printf(StatusChange v) -> typename remove_enum::type { return typename remove_enum::type(v); } -} // namespace tmwa diff --git a/src/io/dir.hpp b/src/io/dir.hpp index 071f309..f6fedbf 100644 --- a/src/io/dir.hpp +++ b/src/io/dir.hpp @@ -20,8 +20,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - #include "fd.hpp" diff --git a/src/io/extract.cpp b/src/io/extract.cpp new file mode 100644 index 0000000..55d3980 --- /dev/null +++ b/src/io/extract.cpp @@ -0,0 +1,220 @@ +#include "extract.hpp" +// extract.cpp - a simple, hierarchical, tokenizer +// +// Copyright © 2013-2014 Ben Longbons +// +// 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 . + +#include + +#include "../strings/astring.hpp" +#include "../strings/xstring.hpp" +#include "../strings/vstring.hpp" + +#include "../poison.hpp" + + +// TODO also pass an io::LineSpan around. +namespace tmwa +{ +bool extract(XString str, XString *rv) +{ + *rv = str; + return true; +} + +bool extract(XString str, RString *rv) +{ + *rv = str; + return true; +} + +bool extract(XString str, AString *rv) +{ + *rv = str; + return true; +} + +bool extract(XString str, std::chrono::nanoseconds *ns) +{ + std::chrono::nanoseconds::rep rep; + if (extract(str, &rep)) + { + *ns = std::chrono::nanoseconds(rep); + return true; + } + if (str.endswith("ns"_s)) + { + if (extract(str.xrslice_h("ns"_s.size()), &rep)) + { + *ns = std::chrono::nanoseconds(rep); + return true; + } + return false; + } + std::chrono::microseconds bigger; + if (extract(str, &bigger)) + { + *ns = bigger; + return *ns == bigger; + } + return false; +} +bool extract(XString str, std::chrono::microseconds *us) +{ + std::chrono::microseconds::rep rep; + if (extract(str, &rep)) + { + *us = std::chrono::microseconds(rep); + return true; + } + if (str.endswith("us"_s)) + { + if (extract(str.xrslice_h("us"_s.size()), &rep)) + { + *us = std::chrono::microseconds(rep); + return true; + } + return false; + } + std::chrono::milliseconds bigger; + if (extract(str, &bigger)) + { + *us = bigger; + return *us == bigger; + } + return false; +} +bool extract(XString str, std::chrono::milliseconds *ms) +{ + std::chrono::milliseconds::rep rep; + if (extract(str, &rep)) + { + *ms = std::chrono::milliseconds(rep); + return true; + } + if (str.endswith("ms"_s)) + { + if (extract(str.xrslice_h("ms"_s.size()), &rep)) + { + *ms = std::chrono::milliseconds(rep); + return true; + } + return false; + } + std::chrono::seconds bigger; + if (extract(str, &bigger)) + { + *ms = bigger; + return *ms == bigger; + } + return false; +} +bool extract(XString str, std::chrono::seconds *s) +{ + std::chrono::seconds::rep rep; + if (extract(str, &rep)) + { + *s = std::chrono::seconds(rep); + return true; + } + if (str.endswith("s"_s)) + { + if (extract(str.xrslice_h("s"_s.size()), &rep)) + { + *s = std::chrono::seconds(rep); + return true; + } + return false; + } + std::chrono::minutes bigger; + if (extract(str, &bigger)) + { + *s = bigger; + return *s == bigger; + } + return false; +} +bool extract(XString str, std::chrono::minutes *min) +{ + std::chrono::minutes::rep rep; + if (extract(str, &rep)) + { + *min = std::chrono::minutes(rep); + return true; + } + if (str.endswith("min"_s)) + { + if (extract(str.xrslice_h("min"_s.size()), &rep)) + { + *min = std::chrono::minutes(rep); + return true; + } + return false; + } + std::chrono::hours bigger; + if (extract(str, &bigger)) + { + *min = bigger; + return *min == bigger; + } + return false; +} +bool extract(XString str, std::chrono::hours *h) +{ + std::chrono::hours::rep rep; + if (extract(str, &rep)) + { + *h = std::chrono::hours(rep); + return true; + } + if (str.endswith("h"_s)) + { + if (extract(str.xrslice_h("h"_s.size()), &rep)) + { + *h = std::chrono::hours(rep); + return true; + } + return false; + } + std::chrono::duration> bigger; + if (extract(str, &bigger)) + { + *h = bigger; + return *h == bigger; + } + return false; +} +bool extract(XString str, std::chrono::duration> *d) +{ + std::chrono::duration>::rep rep; + if (extract(str, &rep)) + { + *d = std::chrono::duration>(rep); + return true; + } + if (str.endswith("d"_s)) + { + if (extract(str.xrslice_h("d"_s.size()), &rep)) + { + *d = std::chrono::duration>(rep); + return true; + } + return false; + } + return false; +} +} // namespace tmwa diff --git a/src/io/extract.hpp b/src/io/extract.hpp new file mode 100644 index 0000000..174243e --- /dev/null +++ b/src/io/extract.hpp @@ -0,0 +1,232 @@ +#pragma once +// extract.hpp - a simple, hierarchical, tokenizer +// +// Copyright © 2012-2013 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include +#include + +#include +#include +#include + +#include "../ints/wrap.hpp" + +#include "../strings/xstring.hpp" + +#include "../compat/time_t.hpp" + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +template +bool do_extract(XString str, T t); + +template::value && !std::is_same::value && !std::is_same::value>::type> +bool extract(XString str, T *iv) +{ + if (!str || str.size() > 20) + return false; + if (!((str.front() == '-' && std::is_signed::value) + || ('0' <= str.front() && str.front() <= '9'))) + return false; + // needs a NUL, but can't always be given one. TODO VString? + char buf[20 + 1]; + std::copy(str.begin(), str.end(), buf); + buf[str.size()] = '\0'; + + char *end; + errno = 0; + if (std::is_signed::value) + { + long long v = strtoll(buf, &end, 10); + if (errno || *end) + return false; + *iv = v; + return *iv == v; + } + else + { + unsigned long long v = strtoull(buf, &end, 10); + if (errno || *end) + return false; + *iv = v; + return *iv == v; + } +} + +inline +bool extract(XString str, TimeT *tv) +{ + return extract(str, &tv->value); +} + +template::value>::type> +bool extract_as_int(XString str, T *iv) +{ + typedef typename underlying_type::type U; + U v; + // defer to integer version + if (!extract(str, &v)) + return false; + // TODO check bounds using enum min/max as in SSCANF + *iv = static_cast(v); + return true; +} + +bool extract(XString str, XString *rv); +bool extract(XString str, RString *rv); +bool extract(XString str, AString *rv); + +template +bool extract(XString str, VString *out) +{ + if (str.size() > N) + return false; + *out = str; + return true; +} + +inline +bool extract(XString str, LString exact) +{ + return str == exact; +} + +template +class LStripper +{ +public: + T impl; +}; + +template +LStripper lstripping(T v) +{ + return {v}; +} + +template +bool extract(XString str, LStripper out) +{ + return extract(str.lstrip(), out.impl); +} + +// basically just a std::tuple +// but it provides its data members publically +template +class Record; +template +class Record +{ +}; +template +class Record +{ +public: + F frist; + Record rest; +public: + Record(F f, R... r) + : frist(f), rest(r...) + {} +}; +template +Record record(T... t) +{ + return Record(t...); +} +template +Record record(T... t) +{ + static_assert(0 < n && n < sizeof...(T), "don't be silly"); + return Record(t...); +} + +template +bool extract(XString str, Record) +{ + return !str; +} + +template +bool extract(XString str, Record rec) +{ + XString::iterator s = std::find(str.begin(), str.end(), split); + XString::iterator s2 = s; + if (s2 != str.end()) + ++s2; + XString head = str.xislice_h(s); + XString tail = str.xislice_t(s2); + if (s == str.end()) + return (extract(head, rec.frist) && n <= 1) + || (!head && n <= 0); + + return (extract(head, rec.frist) || n <= 0) + && extract(tail, rec.rest); +} + +template +struct VRecord +{ + std::vector *arr; +}; + +template +VRecord vrec(std::vector *arr) +{ + return {arr}; +} + +template +bool extract(XString str, VRecord rec) +{ + if (!str) + return true; + XString::iterator s = std::find(str.begin(), str.end(), split); + rec.arr->emplace_back(); + if (s == str.end()) + return extract(str, &rec.arr->back()); + return extract(str.xislice_h(s), &rec.arr->back()) + && extract(str.xislice_t(s + 1), rec); +} + +template +bool do_extract(XString str, T t) +{ + return extract(str, t); +} + +template +bool extract(XString str, Wrapped *w) +{ + return extract(str, &w->_value); +} + +bool extract(XString str, std::chrono::nanoseconds *ns); +bool extract(XString str, std::chrono::microseconds *us); +bool extract(XString str, std::chrono::milliseconds *ms); +bool extract(XString str, std::chrono::seconds *s); +bool extract(XString str, std::chrono::minutes *min); +bool extract(XString str, std::chrono::hours *h); +bool extract(XString str, std::chrono::duration> *d); +} // namespace tmwa diff --git a/src/io/extract_test.cpp b/src/io/extract_test.cpp new file mode 100644 index 0000000..ee4cb08 --- /dev/null +++ b/src/io/extract_test.cpp @@ -0,0 +1,452 @@ +#include "extract.hpp" +// extract_test.cpp - Testsuite for a simple, hierarchical, tokenizer +// +// Copyright © 2013 Ben Longbons +// +// 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 . + +#include + +#include "../strings/xstring.hpp" + +#include "../net/timer.t.hpp" + +#include "../mmo/strs.hpp" + +#include "../high/extract_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 "_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"_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 "_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"_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 "_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"_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 "_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"_s, record<' '>(&x, &y, &z))); + EXPECT_EQ(1, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; + 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(""_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 "_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"_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 "_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"_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 "_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"_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 "_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"_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(" "_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(""_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 "_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"_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 "_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"_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 "_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"_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 "_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"_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(" "_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(""_s, record<' ', 1>(&x, &y, &z))); + EXPECT_EQ(0, x); + EXPECT_EQ(0, y); + EXPECT_EQ(0, z); + x = y = z = 0; +} + +TEST(extract, record_str) +{ + XString 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 "_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 "_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"_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); +} + +TEST(extract, chrono) +{ + std::chrono::nanoseconds ns; + std::chrono::microseconds us; + std::chrono::milliseconds ms; + std::chrono::seconds s; + std::chrono::minutes min; + std::chrono::hours h; + std::chrono::duration> d; + + EXPECT_TRUE(extract("1"_s, &ns)); + EXPECT_EQ(ns, 1_ns); + EXPECT_TRUE(extract("3ns"_s, &ns)); + EXPECT_EQ(ns, 3_ns); + EXPECT_TRUE(extract("4us"_s, &ns)); + EXPECT_EQ(ns, 4_us); + EXPECT_TRUE(extract("5ms"_s, &ns)); + EXPECT_EQ(ns, 5_ms); + EXPECT_TRUE(extract("6s"_s, &ns)); + EXPECT_EQ(ns, 6_s); + EXPECT_TRUE(extract("7min"_s, &ns)); + EXPECT_EQ(ns, 7_min); + EXPECT_TRUE(extract("8h"_s, &ns)); + EXPECT_EQ(ns, 8_h); + EXPECT_TRUE(extract("9d"_s, &ns)); + EXPECT_EQ(ns, 9_d); + + EXPECT_TRUE(extract("1"_s, &us)); + EXPECT_EQ(us, 1_us); + EXPECT_TRUE(extract("4us"_s, &us)); + EXPECT_EQ(us, 4_us); + EXPECT_TRUE(extract("5ms"_s, &us)); + EXPECT_EQ(us, 5_ms); + EXPECT_TRUE(extract("6s"_s, &us)); + EXPECT_EQ(us, 6_s); + EXPECT_TRUE(extract("7min"_s, &us)); + EXPECT_EQ(us, 7_min); + EXPECT_TRUE(extract("8h"_s, &us)); + EXPECT_EQ(us, 8_h); + EXPECT_TRUE(extract("9d"_s, &us)); + EXPECT_EQ(us, 9_d); + + EXPECT_TRUE(extract("1"_s, &ms)); + EXPECT_EQ(ms, 1_ms); + EXPECT_TRUE(extract("5ms"_s, &ms)); + EXPECT_EQ(ms, 5_ms); + EXPECT_TRUE(extract("6s"_s, &ms)); + EXPECT_EQ(ms, 6_s); + EXPECT_TRUE(extract("7min"_s, &ms)); + EXPECT_EQ(ms, 7_min); + EXPECT_TRUE(extract("8h"_s, &ms)); + EXPECT_EQ(ms, 8_h); + EXPECT_TRUE(extract("9d"_s, &ms)); + EXPECT_EQ(ms, 9_d); + + EXPECT_TRUE(extract("1"_s, &s)); + EXPECT_EQ(s, 1_s); + EXPECT_TRUE(extract("6s"_s, &s)); + EXPECT_EQ(s, 6_s); + EXPECT_TRUE(extract("7min"_s, &s)); + EXPECT_EQ(s, 7_min); + EXPECT_TRUE(extract("8h"_s, &s)); + EXPECT_EQ(s, 8_h); + EXPECT_TRUE(extract("9d"_s, &s)); + EXPECT_EQ(s, 9_d); + + EXPECT_TRUE(extract("1"_s, &min)); + EXPECT_EQ(min, 1_min); + EXPECT_TRUE(extract("7min"_s, &min)); + EXPECT_EQ(min, 7_min); + EXPECT_TRUE(extract("8h"_s, &min)); + EXPECT_EQ(min, 8_h); + EXPECT_TRUE(extract("9d"_s, &min)); + EXPECT_EQ(min, 9_d); + + EXPECT_TRUE(extract("1"_s, &h)); + EXPECT_EQ(h, 1_h); + EXPECT_TRUE(extract("8h"_s, &h)); + EXPECT_EQ(h, 8_h); + EXPECT_TRUE(extract("9d"_s, &h)); + EXPECT_EQ(h, 9_d); + + EXPECT_TRUE(extract("1"_s, &d)); + EXPECT_EQ(d, 1_d); + EXPECT_TRUE(extract("9d"_s, &d)); + EXPECT_EQ(d, 9_d); +} +} // namespace tmwa diff --git a/src/io/fd.hpp b/src/io/fd.hpp index d04d5bf..03a8b44 100644 --- a/src/io/fd.hpp +++ b/src/io/fd.hpp @@ -23,8 +23,6 @@ #include #include -#include "../strings/fwd.hpp" - #include "../diagnostics.hpp" diff --git a/src/io/fwd.hpp b/src/io/fwd.hpp index deeb08c..99268f4 100644 --- a/src/io/fwd.hpp +++ b/src/io/fwd.hpp @@ -20,6 +20,12 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +// io/fwd.hpp is rank 4 + namespace tmwa { diff --git a/src/io/read.cpp b/src/io/read.cpp index f3ed293..30620a1 100644 --- a/src/io/read.cpp +++ b/src/io/read.cpp @@ -25,7 +25,7 @@ #include "../strings/zstring.hpp" #include "../strings/literal.hpp" -#include "../io/cxxstdio.hpp" +#include "cxxstdio.hpp" #include "../poison.hpp" diff --git a/src/io/read.hpp b/src/io/read.hpp index 1ec26ca..c1c4882 100644 --- a/src/io/read.hpp +++ b/src/io/read.hpp @@ -20,8 +20,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - #include "dir.hpp" #include "fd.hpp" diff --git a/src/io/write.hpp b/src/io/write.hpp index 1ab05f3..d7d3699 100644 --- a/src/io/write.hpp +++ b/src/io/write.hpp @@ -22,8 +22,6 @@ #include -#include "../strings/fwd.hpp" - #include "dir.hpp" #include "fd.hpp" diff --git a/src/login/fwd.hpp b/src/login/fwd.hpp index 94fe3c0..8a2027b 100644 --- a/src/login/fwd.hpp +++ b/src/login/fwd.hpp @@ -20,6 +20,17 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../mmo/fwd.hpp" // rank 6 +#include "../proto2/fwd.hpp" // rank 8 +#include "../high/fwd.hpp" // rank 9 +#include "../wire/fwd.hpp" // rank 9 +// login/fwd.hpp is rank ∞ because it is an executable + namespace tmwa { diff --git a/src/login/login.cpp b/src/login/login.cpp index a84c96a..fa528ba 100644 --- a/src/login/login.cpp +++ b/src/login/login.cpp @@ -45,23 +45,18 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/lock.hpp" #include "../io/read.hpp" #include "../io/tty.hpp" #include "../io/write.hpp" -#include "../net/packets.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/core.hpp" -#include "../mmo/extract.hpp" #include "../mmo/human_time_diff.hpp" #include "../mmo/ids.hpp" -#include "../mmo/md5more.hpp" -#include "../mmo/mmo.hpp" -#include "../mmo/utils.hpp" #include "../mmo/version.hpp" #include "../proto2/any-user.hpp" @@ -69,6 +64,14 @@ #include "../proto2/login-char.hpp" #include "../proto2/login-user.hpp" +#include "../high/core.hpp" +#include "../high/extract_mmo.hpp" +#include "../high/md5more.hpp" +#include "../high/mmo.hpp" +#include "../high/utils.hpp" + +#include "../wire/packets.hpp" + #include "../poison.hpp" diff --git a/src/login/login.hpp b/src/login/login.hpp index 5900440..88dd4ec 100644 --- a/src/login/login.hpp +++ b/src/login/login.hpp @@ -18,8 +18,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "login.t.hpp" - #include "fwd.hpp" diff --git a/src/login/login.t.hpp b/src/login/login.t.hpp deleted file mode 100644 index f2c775a..0000000 --- a/src/login/login.t.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -// login.t.hpp - externally useful types from login -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include - -#include "../generic/enum.hpp" - - -namespace tmwa -{ -namespace e -{ -enum class VERSION_2 : uint8_t -{ - /// client supports updatehost - UPDATEHOST = 0x01, - /// send servers in forward order - SERVERORDER = 0x02, -}; -ENUM_BITWISE_OPERATORS(VERSION_2) -} -using e::VERSION_2; -} // namespace tmwa diff --git a/src/login/main.cpp b/src/login/main.cpp index 48a471a..4495bda 100644 --- a/src/login/main.cpp +++ b/src/login/main.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "../mmo/core.hpp" +#include "../high/core.hpp" #include "login.hpp" diff --git a/src/map/atcommand.cpp b/src/map/atcommand.cpp index bf64473..d3e215f 100644 --- a/src/map/atcommand.cpp +++ b/src/map/atcommand.cpp @@ -37,23 +37,26 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../io/write.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" +#include "../net/timestamp-utils.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/core.hpp" -#include "../mmo/extract.hpp" +#include "../mmo/cxxstdio_enums.hpp" #include "../mmo/extract_enums.hpp" #include "../mmo/human_time_diff.hpp" #include "../mmo/ids.hpp" -#include "../mmo/mmo.hpp" -#include "../mmo/utils.hpp" #include "../mmo/version.hpp" +#include "../high/core.hpp" +#include "../high/extract_mmo.hpp" +#include "../high/mmo.hpp" +#include "../high/utils.hpp" + #include "battle.hpp" #include "chrif.hpp" #include "clif.hpp" diff --git a/src/map/atcommand.hpp b/src/map/atcommand.hpp index 4bf5277..745039d 100644 --- a/src/map/atcommand.hpp +++ b/src/map/atcommand.hpp @@ -22,14 +22,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../net/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/battle.cpp b/src/map/battle.cpp index ce10c5c..63dc957 100644 --- a/src/map/battle.cpp +++ b/src/map/battle.cpp @@ -32,10 +32,12 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" #include "../mmo/config_parse.hpp" +#include "../mmo/cxxstdio_enums.hpp" + +#include "../high/utils.hpp" #include "clif.hpp" #include "itemdb.hpp" diff --git a/src/map/battle.hpp b/src/map/battle.hpp index 5f47b70..4a69b8e 100644 --- a/src/map/battle.hpp +++ b/src/map/battle.hpp @@ -24,15 +24,11 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - #include "../net/timer.t.hpp" -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" #include "map.t.hpp" -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa diff --git a/src/map/chrif.cpp b/src/map/chrif.cpp index 090cccf..09c238c 100644 --- a/src/map/chrif.cpp +++ b/src/map/chrif.cpp @@ -29,15 +29,16 @@ #include "../io/cxxstdio.hpp" #include "../net/ip.hpp" -#include "../net/packets.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" +#include "../net/timestamp-utils.hpp" #include "../proto2/char-map.hpp" #include "../mmo/human_time_diff.hpp" -#include "../mmo/mmo.hpp" -#include "../mmo/utils.hpp" +#include "../high/mmo.hpp" + +#include "../wire/packets.hpp" #include "battle.hpp" #include "clif.hpp" diff --git a/src/map/chrif.hpp b/src/map/chrif.hpp index 4711bc5..4bd00aa 100644 --- a/src/map/chrif.hpp +++ b/src/map/chrif.hpp @@ -22,14 +22,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../net/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/clif.cpp b/src/map/clif.cpp index a5b7278..430d928 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -36,22 +36,25 @@ #include "../strings/xstring.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/write.hpp" #include "../net/ip.hpp" -#include "../net/packets.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" +#include "../net/timestamp-utils.hpp" #include "../proto2/any-user.hpp" #include "../proto2/char-map.hpp" #include "../proto2/map-user.hpp" -#include "../mmo/md5more.hpp" -#include "../mmo/utils.hpp" +#include "../mmo/cxxstdio_enums.hpp" #include "../mmo/version.hpp" +#include "../high/md5more.hpp" + +#include "../wire/packets.hpp" + #include "atcommand.hpp" #include "battle.hpp" #include "chrif.hpp" @@ -5675,38 +5678,4 @@ void do_init_clif(void) { make_listen_port(map_port, SessionParsers{.func_parse= clif_parse, .func_delete= clif_delete}); } - -bool extract(XString str, DIR *d) -{ - unsigned di; - if (extract(str, &di) && di < 8) - { - *d = static_cast(di); - return true; - } - const struct - { - LString str; - DIR d; - } dirs[] = - { - {"S"_s, DIR::S}, - {"SW"_s, DIR::SW}, - {"W"_s, DIR::W}, - {"NW"_s, DIR::NW}, - {"N"_s, DIR::N}, - {"NE"_s, DIR::NE}, - {"E"_s, DIR::E}, - {"SE"_s, DIR::SE}, - }; - for (auto& pair : dirs) - { - if (str == pair.str) - { - *d = pair.d; - return true; - } - } - return false; -} } // namespace tmwa diff --git a/src/map/clif.hpp b/src/map/clif.hpp index 9873592..24f4b80 100644 --- a/src/map/clif.hpp +++ b/src/map/clif.hpp @@ -20,25 +20,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" #include "fwd.hpp" #include -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" +#include "../high/mmo.hpp" #include "../net/timer.t.hpp" -#include "../mmo/fwd.hpp" -#include "../mmo/mmo.hpp" - #include "battle.t.hpp" #include "map.t.hpp" #include "pc.t.hpp" -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa @@ -189,6 +184,4 @@ int clif_GM_kick(dumb_ptr sd, dumb_ptr tsd, int clif_foreachclient(std::function)>); void do_init_clif(void); - -bool extract(XString, DIR *); } // namespace tmwa diff --git a/src/map/clif.t.hpp b/src/map/clif.t.hpp deleted file mode 100644 index 0f8cdbf..0000000 --- a/src/map/clif.t.hpp +++ /dev/null @@ -1,717 +0,0 @@ -#pragma once -// clif.t.hpp - Network interface to the client. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include - -#include "../ints/little.hpp" - -#include "../compat/iter.hpp" - -#include "../generic/enum.hpp" - -#include "../mmo/consts.hpp" -#include "../mmo/enums.hpp" - - -namespace tmwa -{ -namespace e -{ -// [Fate] status.option properties. These are persistent status changes. -// IDs that are not listed are not used in the code (to the best of my knowledge) -enum class Opt0 : uint16_t -{ - ZERO = 0x0000, - - // [Fate] This is the GM `@hide' flag - HIDE = 0x0040, - // [Fate] Complete invisibility to other clients - INVISIBILITY = 0x1000, - - // ? - REAL_ANY_HIDE = HIDE, -}; -enum class Opt1 : uint16_t -{ - ZERO = 0, - _stone1 = 1, - _freeze = 2, - _stan = 3, - _sleep = 4, - _stone6 = 6, -}; -enum class Opt2 : uint16_t -{ - ZERO = 0x0000, - _poison = 0x0001, - _curse = 0x0002, - _silence = 0x0004, - BLIND = 0x0010, - _speedpotion0 = 0x0020, - _signumcrucis = 0x0040, - _atkpot = 0x0080, - _heal = 0x0100, - _slowpoison = 0x0200, -}; -enum class Opt3 : uint16_t -{ - ZERO = 0x0000, - _concentration = 0x0001, - _overthrust = 0x0002, - _energycoat = 0x0004, - _explosionspirits = 0x0008, - _steelbody = 0x0010, - _berserk = 0x0080, - - _marionette = 0x0400, - _assumptio = 0x0800, -}; - -ENUM_BITWISE_OPERATORS(Opt0) -ENUM_BITWISE_OPERATORS(Opt2) -ENUM_BITWISE_OPERATORS(Opt3) -} -using e::Opt0; -using e::Opt1; -using e::Opt2; -using e::Opt3; - - -enum class ItemType : uint8_t -{ - USE = 0, // in eA, healing only - _1 = 1, // unused - _2 = 2, // in eA, other usable items - JUNK = 3, // "useless" items (e.g. quests) - WEAPON = 4, // all weapons - ARMOR = 5, // all other equipment - _6 = 6, // in eA, card - _7 = 7, // in eA, pet egg - _8 = 8, // in eA, pet equipment - _9 = 9, // unused - ARROW = 10, // ammo - _11 = 11, // in eA, delayed use (special script) -}; - -enum class BeingRemoveWhy : uint8_t -{ - // general disappearance - GONE = 0, - // only case handled specially in client - DEAD = 1, - QUIT = 2, - WARPED = 3, - // handled specially in clif_clearchar - sent as 0 over network - DISGUISE = 9, - - // handled speciall in mob_warp - not actually sent over network - NEGATIVE1 = 0xff, -}; - -enum class PickupFail : uint8_t -{ - OKAY = 0, - BAD_ITEM = 1, - TOO_HEAVY = 2, - TOO_FAR = 3, - INV_FULL = 4, - STACK_FULL = 5, - DROP_STEAL = 6, -}; - -// this is used for both input and output -// different values are valid in 0x0089 vs 0x008a -enum class DamageType : uint8_t -{ - NORMAL = 0x00, - TAKEITEM = 0x01, - SIT = 0x02, - STAND = 0x03, - RETURNED = 0x04, - CONTINUOUS = 0x07, - DOUBLED = 0x08, - CRITICAL = 0x0a, - FLEE2 = 0x0b, -}; - -enum class LOOK : uint8_t -{ - BASE = 0, - HAIR = 1, - WEAPON = 2, - HEAD_BOTTOM = 3, - HEAD_TOP = 4, - HEAD_MID = 5, - HAIR_COLOR = 6, - CLOTHES_COLOR = 7, - SHIELD = 8, - SHOES = 9, - GLOVES = 10, - CAPE = 11, - MISC1 = 12, - MISC2 = 13, - - COUNT, -}; - -// Note: there is also a typedef by this name in -// but we should be fine since we never include it. -// (in the long term we should still rename this though) -enum class DIR : uint8_t -{ - S = 0, - SW = 1, - W = 2, - NW = 3, - N = 4, - NE = 5, - E = 6, - SE = 7, - - COUNT, -}; - -constexpr -earray dirx //= -{{ - 0, -1, -1, -1, 0, 1, 1, 1, -}}, diry //= -{{ - 1, 1, 0, -1, -1, -1, 0, 1, -}}; - -constexpr -bool dir_is_diagonal(DIR d) -{ - return static_cast(d) & 1; -} - - -enum class SP : uint16_t -{ - // sent to client - SPEED = 0, - - // when used as "no stat" - ZERO = 0, - - // sent to client - BASEEXP = 1, - // sent to client - JOBEXP = 2, -#if 0 - KARMA = 3, -#endif - - // sent to client - HP = 5, - // sent to client - MAXHP = 6, - // sent to client - SP = 7, - // sent to client - MAXSP = 8, - // sent to client - STATUSPOINT = 9, - - // sent to client - BASELEVEL = 11, - // sent to client - SKILLPOINT = 12, - // sent to client - STR = 13, - // sent to client - AGI = 14, - // sent to client - VIT = 15, - // sent to client - INT = 16, - // sent to client - DEX = 17, - // sent to client - LUK = 18, - CLASS = 19, - // sent to client - ZENY = 20, - SEX = 21, - // sent to client - NEXTBASEEXP = 22, - // sent to client - NEXTJOBEXP = 23, - // sent to client - WEIGHT = 24, - // sent to client - MAXWEIGHT = 25, - - // sent to client - USTR = 32, - // sent to client - UAGI = 33, - // sent to client - UVIT = 34, - // sent to client - UINT = 35, - // sent to client - UDEX = 36, - // sent to client - ULUK = 37, - - // sent to client - ATK1 = 41, - // sent to client - ATK2 = 42, - // sent to client - MATK1 = 43, - // sent to client - MATK2 = 44, - // sent to client - DEF1 = 45, - // sent to client - DEF2 = 46, - // sent to client - MDEF1 = 47, - // sent to client - MDEF2 = 48, - // sent to client - HIT = 49, - // sent to client - FLEE1 = 50, - // sent to client - FLEE2 = 51, - // sent to client - CRITICAL = 52, - // sent to client - ASPD = 53, - - // sent to client - JOBLEVEL = 55, - -#if 0 - PARTNER = 57, - CART = 58, - FAME = 59, - UNBREAKABLE = 60, -#endif - - DEAF = 70, - - // sent to client - GM = 500, - - // sent to client - ATTACKRANGE = 1000, -#if 0 - ATKELE = 1001, -#endif -#if 0 - DEFELE = 1002, -#endif -#if 0 - CASTRATE = 1003, -#endif - MAXHPRATE = 1004, -#if 0 - MAXSPRATE = 1005, -#endif -#if 0 - SPRATE = 1006, -#endif - -#if 0 - ADDEFF = 1012, -#endif -#if 0 - RESEFF = 1013, -#endif - BASE_ATK = 1014, - ASPD_RATE = 1015, - HP_RECOV_RATE = 1016, -#if 0 - SP_RECOV_RATE = 1017, -#endif -#if 0 - SPEED_RATE = 1018, -#endif - CRITICAL_DEF = 1019, -#if 0 - NEAR_ATK_DEF = 1020, -#endif -#if 0 - LONG_ATK_DEF = 1021, -#endif -#if 0 - DOUBLE_RATE = 1022, -#endif - DOUBLE_ADD_RATE = 1023, -#if 0 - MATK = 1024, -#endif -#if 0 - MATK_RATE = 1025, -#endif -#if 0 - IGNORE_DEF_ELE = 1026, -#endif -#if 0 - IGNORE_DEF_RACE = 1027, -#endif -#if 0 - ATK_RATE = 1028, -#endif - SPEED_ADDRATE = 1029, -#if 0 - ASPD_ADDRATE = 1030, -#endif -#if 0 - MAGIC_ATK_DEF = 1031, -#endif -#if 0 - MISC_ATK_DEF = 1032, -#endif -#if 0 - IGNORE_MDEF_ELE = 1033, -#endif -#if 0 - IGNORE_MDEF_RACE = 1034, -#endif - -#if 0 - PERFECT_HIT_RATE = 1038, -#endif -#if 0 - PERFECT_HIT_ADD_RATE = 1039, -#endif -#if 0 - CRITICAL_RATE = 1040, -#endif -#if 0 - GET_ZENY_NUM = 1041, -#endif -#if 0 - ADD_GET_ZENY_NUM = 1042, -#endif - -#if 0 - ADD_MONSTER_DROP_ITEM = 1047, -#endif -#if 0 - DEF_RATIO_ATK_ELE = 1048, -#endif -#if 0 - DEF_RATIO_ATK_RACE = 1049, -#endif -#if 0 - ADD_SPEED = 1050, -#endif -#if 0 - HIT_RATE = 1051, -#endif -#if 0 - FLEE_RATE = 1052, -#endif -#if 0 - FLEE2_RATE = 1053, -#endif - DEF_RATE = 1054, - DEF2_RATE = 1055, -#if 0 - MDEF_RATE = 1056, -#endif -#if 0 - MDEF2_RATE = 1057, -#endif -#if 0 - SPLASH_RANGE = 1058, -#endif -#if 0 - SPLASH_ADD_RANGE = 1059, -#endif - - HP_DRAIN_RATE = 1061, -#if 0 - SP_DRAIN_RATE = 1062, -#endif -#if 0 - SHORT_WEAPON_DAMAGE_RETURN = 1063, -#endif -#if 0 - LONG_WEAPON_DAMAGE_RETURN = 1064, -#endif - -#if 0 - ADDEFF2 = 1067, -#endif - BREAK_WEAPON_RATE = 1068, - BREAK_ARMOR_RATE = 1069, - ADD_STEAL_RATE = 1070, - MAGIC_DAMAGE_RETURN = 1071, -#if 0 - RANDOM_ATTACK_INCREASE = 1072, -#endif -}; - -constexpr -SP attr_to_sp(ATTR attr) -{ - return static_cast(static_cast(attr) + static_cast(SP::STR)); -} - -constexpr -ATTR sp_to_attr(SP sp) -{ - return static_cast(static_cast(sp) - static_cast(SP::STR)); -} - -constexpr -SP attr_to_usp(ATTR attr) -{ - return static_cast(static_cast(attr) + static_cast(SP::USTR)); -} - -constexpr -ATTR usp_to_attr(SP sp) -{ - return static_cast(static_cast(sp) - static_cast(SP::USTR)); -} - -constexpr -SP sp_to_usp(SP sp) -{ - return attr_to_usp(sp_to_attr(sp)); -} - -constexpr -SP usp_to_sp(SP sp) -{ - return attr_to_sp(usp_to_attr(sp)); -} - - -// xxxx xxxx xxyy yyyy yyyy dddd -struct NetPosition1 -{ - Byte data[3]; -}; - -struct Position1 -{ - uint16_t x, y; - DIR dir; -}; - -inline -bool native_to_network(NetPosition1 *network, Position1 native) -{ - uint16_t x = native.x; - uint16_t y = native.y; - uint8_t d = static_cast(native.dir); - - uint8_t *p = reinterpret_cast(network); - p[0] = x >> 2; - p[1] = (x << 6) | ((y >> 4) & 0x3f); - p[2] = y << 4 | d; - - return x < 1024 && y < 1024 && d < 16; -} - -inline -bool network_to_native(Position1 *native, NetPosition1 network) -{ - const uint8_t *p = reinterpret_cast(&network); - native->x = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); - native->y = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); - uint8_t d = p[2] & 0x0f; - native->dir = static_cast(d); - return d < 8; -} - -// x0xx xxxx xxy0 yyyy yyyy x1xx xxxx xxy1 yyyy yyyy -struct NetPosition2 -{ - Byte data[5]; -}; - -struct Position2 -{ - uint16_t x0, y0; - uint16_t x1, y1; -}; - -inline -bool native_to_network(NetPosition2 *network, Position2 native) -{ - uint16_t x0 = native.x0; - uint16_t y0 = native.y0; - uint16_t x1 = native.x1; - uint16_t y1 = native.y1; - - uint8_t *p = reinterpret_cast(network); - p[0] = x0 >> 2; - p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f); - p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f); - p[3] = (x1 << 2) | ((y1 >> 8) & 0x03); - p[4] = y1; - - return x0 < 1024 && y0 < 1024 && x1 < 1024 && y1 < 1024; -} - -inline -bool network_to_native(Position2 *native, NetPosition2 network) -{ - const uint8_t *p = reinterpret_cast(&network); - native->x0 = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); - native->y0 = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); - native->x1 = (p[2] & (0x3ff >> 6)) << 6 | p[3] >> (8 - 6); - native->y1 = (p[3] & (0x3ff >> 8)) << 8 | p[4] >> (8 - 8); - return true; -} - -struct IOff2; -struct SOff1; - -struct IOff0 -{ - uint16_t index; - - bool ok() const - { return get0() < MAX_INVENTORY; } - uint16_t get0() const - { return index; } - static IOff0 from(uint16_t i) - { return IOff0{i}; } - static IteratorPair> iter() - { return {IOff0::from(0), IOff0::from(MAX_INVENTORY)}; } - friend uint16_t convert_for_printf(IOff0 i0) { return i0.index; } - - IOff0& operator ++() { ++index; return *this; } - friend bool operator == (IOff0 l, IOff0 r) { return l.index == r.index; } - friend bool operator != (IOff0 l, IOff0 r) { return !(l == r); } - IOff2 shift() const; - - IOff0() : index(0) {} -private: - explicit IOff0(uint16_t i) : index(i) {} -}; - -struct SOff0 -{ - uint16_t index; - - bool ok() const - { return get0() < MAX_STORAGE; } - uint16_t get0() const - { return index; } - static SOff0 from(uint16_t i) - { return SOff0{i}; } - static IteratorPair> iter() - { return {SOff0::from(0), SOff0::from(MAX_STORAGE)}; } - friend uint16_t convert_for_printf(SOff0 s0) { return s0.index; } - - SOff0& operator ++() { ++index; return *this; } - friend bool operator == (SOff0 l, SOff0 r) { return l.index == r.index; } - friend bool operator != (SOff0 l, SOff0 r) { return !(l == r); } - SOff1 shift() const; - - SOff0() : index(0) {} -private: - explicit SOff0(uint16_t i) : index(i) {} -}; - -struct IOff2 -{ - uint16_t index; - - bool ok() const - { return get2() < MAX_INVENTORY; } - uint16_t get2() const - { return index - 2; } - static IOff2 from(uint16_t i) - { return IOff2{static_cast(i + 2)}; } - static IteratorPair> iter() - { return {IOff2::from(0), IOff2::from(MAX_INVENTORY)}; } - - IOff2& operator ++() { ++index; return *this; } - friend bool operator == (IOff2 l, IOff2 r) { return l.index == r.index; } - friend bool operator != (IOff2 l, IOff2 r) { return !(l == r); } - IOff0 unshift() const - { return IOff0::from(get2()); } - - IOff2() : index(0) {} -private: - explicit IOff2(uint16_t i) : index(i) {} -}; - -struct SOff1 -{ - uint16_t index; - - bool ok() const - { return get1() < MAX_STORAGE; } - uint16_t get1() const - { return index - 1; } - static SOff1 from(uint16_t i) - { return SOff1{static_cast(i + 1)}; } - static IteratorPair> iter() - { return {SOff1::from(0), SOff1::from(MAX_STORAGE)}; } - - SOff1& operator ++() { ++index; return *this; } - friend bool operator == (SOff1 l, SOff1 r) { return l.index == r.index; } - friend bool operator != (SOff1 l, SOff1 r) { return !(l == r); } - SOff0 unshift() const - { return SOff0::from(get1()); } - - SOff1() : index(0) {} -private: - explicit SOff1(uint16_t i) : index(i) {} -}; - -inline IOff2 IOff0::shift() const -{ return IOff2::from(get0()); } -inline SOff1 SOff0::shift() const -{ return SOff1::from(get0()); } - -inline -bool native_to_network(Little16 *network, IOff2 native) -{ - return native_to_network(network, native.index); -} - -inline -bool network_to_native(IOff2 *native, Little16 network) -{ - return network_to_native(&native->index, network); -} - -inline -bool native_to_network(Little16 *network, SOff1 native) -{ - return native_to_network(network, native.index); -} - -inline -bool network_to_native(SOff1 *native, Little16 network) -{ - return network_to_native(&native->index, network); -} -} // namespace tmwa diff --git a/src/map/fwd.hpp b/src/map/fwd.hpp index 578b08a..f998b77 100644 --- a/src/map/fwd.hpp +++ b/src/map/fwd.hpp @@ -22,11 +22,24 @@ #include +#include "../ints/fwd.hpp" // rank 1 +#include "../range/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../sexpr/fwd.hpp" // rank 5 +#include "../mmo/fwd.hpp" // rank 6 +#include "../proto2/fwd.hpp" // rank 8 +#include "../high/fwd.hpp" // rank 9 +#include "../wire/fwd.hpp" // rank 9 +// map/fwd.hpp is rank ∞ because it is an executable + namespace tmwa { // meh, add more when I feel like it -class BlockId; struct block_list; struct map_session_data; struct npc_data; @@ -38,11 +51,6 @@ class npc_data_script; class npc_data_shop; class npc_data_warp; class npc_data_message; -struct NpcEvent; -struct MobName; -struct NpcName; -struct ScriptLabel; -struct ItemName; struct item_data; diff --git a/src/map/grfio.cpp b/src/map/grfio.cpp index 4a1656b..8821374 100644 --- a/src/map/grfio.cpp +++ b/src/map/grfio.cpp @@ -33,10 +33,11 @@ #include "../strings/zstring.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" -#include "../mmo/extract.hpp" -#include "../mmo/mmo.hpp" +#include "../high/extract_mmo.hpp" +#include "../high/mmo.hpp" #include "../poison.hpp" diff --git a/src/map/grfio.hpp b/src/map/grfio.hpp index d2ab058..4cd4092 100644 --- a/src/map/grfio.hpp +++ b/src/map/grfio.hpp @@ -26,10 +26,6 @@ #include -#include "../strings/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/intif.cpp b/src/map/intif.cpp index 6cc3772..c6821b6 100644 --- a/src/map/intif.cpp +++ b/src/map/intif.cpp @@ -29,13 +29,14 @@ #include "../io/cxxstdio.hpp" -#include "../net/packets.hpp" #include "../net/socket.hpp" -#include "../mmo/mmo.hpp" +#include "../high/mmo.hpp" #include "../proto2/char-map.hpp" +#include "../wire/packets.hpp" + #include "battle.hpp" #include "chrif.hpp" #include "clif.hpp" diff --git a/src/map/intif.hpp b/src/map/intif.hpp index 00f3c49..d51ca11 100644 --- a/src/map/intif.hpp +++ b/src/map/intif.hpp @@ -22,16 +22,6 @@ #include "fwd.hpp" -#include "../compat/fwd.hpp" - -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../net/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/itemdb.cpp b/src/map/itemdb.cpp index 5ffa725..2e3d0c5 100644 --- a/src/map/itemdb.cpp +++ b/src/map/itemdb.cpp @@ -29,10 +29,10 @@ #include "../generic/db.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/extract.hpp" #include "../mmo/extract_enums.hpp" #include "script-parse.hpp" diff --git a/src/map/itemdb.hpp b/src/map/itemdb.hpp index fccfa23..fcc92c4 100644 --- a/src/map/itemdb.hpp +++ b/src/map/itemdb.hpp @@ -23,7 +23,7 @@ #include "fwd.hpp" #include "../mmo/ids.hpp" -#include "../mmo/mmo.hpp" +#include "../high/mmo.hpp" #include "map.t.hpp" #include "script-buffer.hpp" diff --git a/src/map/magic-expr.cpp b/src/map/magic-expr.cpp index 4afa3bc..9cc4e33 100644 --- a/src/map/magic-expr.cpp +++ b/src/map/magic-expr.cpp @@ -33,7 +33,8 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" + +#include "../mmo/cxxstdio_enums.hpp" #include "battle.hpp" #include "itemdb.hpp" diff --git a/src/map/magic-expr.hpp b/src/map/magic-expr.hpp index 2a4b4be..8b88142 100644 --- a/src/map/magic-expr.hpp +++ b/src/map/magic-expr.hpp @@ -21,15 +21,9 @@ #include "fwd.hpp" -#include "../generic/fwd.hpp" - -#include "../range/fwd.hpp" - #include "../strings/zstring.hpp" #include "../strings/literal.hpp" -#include "../mmo/fwd.hpp" - #include "magic-interpreter.t.hpp" diff --git a/src/map/magic-interpreter-base.cpp b/src/map/magic-interpreter-base.cpp index be9a61a..7fde979 100644 --- a/src/map/magic-interpreter-base.cpp +++ b/src/map/magic-interpreter-base.cpp @@ -25,7 +25,8 @@ #include "../strings/xstring.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" + +#include "../mmo/cxxstdio_enums.hpp" #include "../net/timer.hpp" diff --git a/src/map/magic-interpreter-base.hpp b/src/map/magic-interpreter-base.hpp index 4bb41a0..2557ecb 100644 --- a/src/map/magic-interpreter-base.hpp +++ b/src/map/magic-interpreter-base.hpp @@ -21,12 +21,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/magic-interpreter.hpp b/src/map/magic-interpreter.hpp index 09642cb..547e294 100644 --- a/src/map/magic-interpreter.hpp +++ b/src/map/magic-interpreter.hpp @@ -27,21 +27,17 @@ #include -#include "../strings/fwd.hpp" #include "../strings/rstring.hpp" -#include "../generic/fwd.hpp" - #include "../sexpr/variant.hpp" #include "../net/timer.t.hpp" #include "../mmo/ids.hpp" -#include "../mmo/utils.hpp" #include "map.hpp" #include "script-buffer.hpp" -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa diff --git a/src/map/magic-stmt.cpp b/src/map/magic-stmt.cpp index b532ec8..d5e1a15 100644 --- a/src/map/magic-stmt.cpp +++ b/src/map/magic-stmt.cpp @@ -29,7 +29,8 @@ #include "../generic/random2.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" + +#include "../mmo/cxxstdio_enums.hpp" #include "../net/timer.hpp" diff --git a/src/map/magic-stmt.hpp b/src/map/magic-stmt.hpp index 0385858..cdbd40f 100644 --- a/src/map/magic-stmt.hpp +++ b/src/map/magic-stmt.hpp @@ -21,13 +21,9 @@ #include "fwd.hpp" -#include "../range/fwd.hpp" - #include "../strings/zstring.hpp" -#include "../generic/fwd.hpp" - -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa diff --git a/src/map/magic.hpp b/src/map/magic.hpp index a420872..8c1ef84 100644 --- a/src/map/magic.hpp +++ b/src/map/magic.hpp @@ -21,12 +21,8 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - #include "map.t.hpp" -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa diff --git a/src/map/main.cpp b/src/map/main.cpp index c16f642..a54bb3f 100644 --- a/src/map/main.cpp +++ b/src/map/main.cpp @@ -17,7 +17,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "../mmo/core.hpp" +#include "../high/core.hpp" #include "map.hpp" diff --git a/src/map/map.cpp b/src/map/map.cpp index dbb54d6..9ae865f 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -45,20 +45,21 @@ #include "../generic/random2.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../io/tty.hpp" #include "../io/write.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" +#include "../net/timestamp-utils.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/core.hpp" -#include "../mmo/extract.hpp" -#include "../mmo/utils.hpp" +#include "../mmo/cxxstdio_enums.hpp" #include "../mmo/version.hpp" +#include "../high/core.hpp" + #include "atcommand.hpp" #include "battle.hpp" #include "chrif.hpp" @@ -127,11 +128,6 @@ VString<49> convert_for_printf(NpcEvent ev) { return STRNPRINTF(50, "%s::%s"_fmt, ev.npc, ev.label); } -bool extract(XString str, NpcEvent *ev) -{ - XString mid; - return extract(str, record<':'>(&ev->npc, &mid, &ev->label)) && !mid; -} /*========================================== * 全map鯖総計での接続数設定 diff --git a/src/map/map.hpp b/src/map/map.hpp index cb4273f..183b74d 100644 --- a/src/map/map.hpp +++ b/src/map/map.hpp @@ -30,7 +30,6 @@ #include "../ints/udl.hpp" -#include "../strings/fwd.hpp" #include "../strings/rstring.hpp" #include "../strings/astring.hpp" #include "../strings/vstring.hpp" @@ -42,15 +41,13 @@ #include "../net/socket.hpp" #include "../net/timer.t.hpp" -#include "../mmo/utils.hpp" - #include "battle.t.hpp" -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" #include "mapflag.hpp" #include "mob.t.hpp" #include "script-buffer.hpp" #include "script-persist.hpp" -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa @@ -69,35 +66,6 @@ constexpr int MAX_DROP_PER_MAP = 48; constexpr interval_t DEFAULT_AUTOSAVE_INTERVAL = 1_min; -// formerly VString<49>, as name::label -struct NpcEvent -{ - NpcName npc; - ScriptLabel label; - - explicit operator bool() - { - return npc || label; - } - bool operator !() - { - return !bool(*this); - } - - friend bool operator == (const NpcEvent& l, const NpcEvent& r) - { - return l.npc == r.npc && l.label == r.label; - } - - friend bool operator < (const NpcEvent& l, const NpcEvent& r) - { - return l.npc < r.npc || (l.npc == r.npc && l.label < r.label); - } - - friend VString<49> convert_for_printf(NpcEvent ev); -}; -bool extract(XString str, NpcEvent *ev); - extern map_local undefined_gat; struct block_list diff --git a/src/map/map.t.hpp b/src/map/map.t.hpp index b475f9b..e8a62bc 100644 --- a/src/map/map.t.hpp +++ b/src/map/map.t.hpp @@ -29,7 +29,7 @@ #include "../generic/enum.hpp" #include "../mmo/ids.hpp" -#include "../mmo/mmo.hpp" +#include "../high/mmo.hpp" namespace tmwa @@ -191,11 +191,6 @@ ENUM_BITWISE_OPERATORS(MapCell) } using e::MapCell; -struct MobName : VString<23> {}; -struct NpcName : VString<23> {}; -struct ScriptLabel : VString<23> {}; -struct ItemName : VString<23> {}; - inline BlockId account_to_block(AccountId a) { return wrap(unwrap(a)); } inline diff --git a/src/map/mapflag.cpp b/src/map/mapflag.cpp index be2ae67..91dfe8d 100644 --- a/src/map/mapflag.cpp +++ b/src/map/mapflag.cpp @@ -18,6 +18,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include "../strings/xstring.hpp" + #include "../poison.hpp" diff --git a/src/map/mapflag.hpp b/src/map/mapflag.hpp index 6d046fa..d964405 100644 --- a/src/map/mapflag.hpp +++ b/src/map/mapflag.hpp @@ -22,8 +22,6 @@ #include -#include "../mmo/extract.hpp" // TODO remove this (requires specializing the *other* half) - namespace tmwa { diff --git a/src/map/mob.cpp b/src/map/mob.cpp index a2932d0..cab17a0 100644 --- a/src/map/mob.cpp +++ b/src/map/mob.cpp @@ -36,14 +36,14 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../net/socket.hpp" #include "../net/timer.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/extract.hpp" +#include "../mmo/cxxstdio_enums.hpp" #include "../mmo/extract_enums.hpp" #include "battle.hpp" diff --git a/src/map/mob.hpp b/src/map/mob.hpp index c4fcce1..6f6fb47 100644 --- a/src/map/mob.hpp +++ b/src/map/mob.hpp @@ -24,16 +24,15 @@ #include "fwd.hpp" -#include "../generic/fwd.hpp" #include "../generic/enum.hpp" #include "../generic/random.t.hpp" #include "../net/timer.t.hpp" #include "battle.t.hpp" -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" #include "map.hpp" -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" namespace tmwa diff --git a/src/map/npc-internal.hpp b/src/map/npc-internal.hpp index 65cef3d..4ddcc84 100644 --- a/src/map/npc-internal.hpp +++ b/src/map/npc-internal.hpp @@ -23,8 +23,6 @@ #include "npc.hpp" #include "fwd.hpp" -#include "../generic/fwd.hpp" - namespace tmwa { diff --git a/src/map/npc-parse.cpp b/src/map/npc-parse.cpp index f5b6a07..81a5ba2 100644 --- a/src/map/npc-parse.cpp +++ b/src/map/npc-parse.cpp @@ -31,10 +31,13 @@ #include "../generic/enum.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../mmo/config_parse.hpp" +#include "../high/extract_mmo.hpp" + #include "battle.hpp" #include "clif.hpp" #include "itemdb.hpp" diff --git a/src/map/npc-parse.hpp b/src/map/npc-parse.hpp index 0d66aa7..a9cf300 100644 --- a/src/map/npc-parse.hpp +++ b/src/map/npc-parse.hpp @@ -22,14 +22,6 @@ #include "fwd.hpp" -#include "../compat/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../strings/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/npc.cpp b/src/map/npc.cpp index 471553b..304224a 100644 --- a/src/map/npc.cpp +++ b/src/map/npc.cpp @@ -38,12 +38,10 @@ #include "../generic/db.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../net/timer.hpp" -#include "../mmo/extract.hpp" -#include "../mmo/utils.hpp" - #include "../proto2/map-user.hpp" #include "battle.hpp" diff --git a/src/map/npc.hpp b/src/map/npc.hpp index 67a62a9..cb42dbd 100644 --- a/src/map/npc.hpp +++ b/src/map/npc.hpp @@ -26,14 +26,8 @@ #include "../range/slice.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - #include "../net/timer.t.hpp" -#include "../proto2/fwd.hpp" - #include "map.hpp" #include "script-call.t.hpp" diff --git a/src/map/party.cpp b/src/map/party.cpp index 45c406a..8150743 100644 --- a/src/map/party.cpp +++ b/src/map/party.cpp @@ -32,7 +32,7 @@ #include "../net/timer.hpp" #include "../mmo/ids.hpp" -#include "../mmo/mmo.hpp" +#include "../high/mmo.hpp" #include "battle.hpp" #include "clif.hpp" diff --git a/src/map/party.hpp b/src/map/party.hpp index 466ee6a..a3f28e3 100644 --- a/src/map/party.hpp +++ b/src/map/party.hpp @@ -24,14 +24,6 @@ #include -#include "../compat/fwd.hpp" - -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/path.cpp b/src/map/path.cpp index 7f9a657..3c05d52 100644 --- a/src/map/path.cpp +++ b/src/map/path.cpp @@ -31,7 +31,7 @@ #include "../io/cxxstdio.hpp" -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" #include "map.hpp" #include "../poison.hpp" diff --git a/src/map/path.hpp b/src/map/path.hpp index a588f1b..49dac7f 100644 --- a/src/map/path.hpp +++ b/src/map/path.hpp @@ -22,8 +22,6 @@ #include "fwd.hpp" -#include "../compat/fwd.hpp" - namespace tmwa { diff --git a/src/map/pc.cpp b/src/map/pc.cpp index 68d478e..1e7d295 100644 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -37,12 +37,12 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" #include "../io/read.hpp" -#include "../net/timer.hpp" +#include "../mmo/cxxstdio_enums.hpp" -#include "../mmo/utils.hpp" +#include "../net/timer.hpp" +#include "../net/timestamp-utils.hpp" #include "../proto2/char-map.hpp" diff --git a/src/map/pc.hpp b/src/map/pc.hpp index 605915e..9795443 100644 --- a/src/map/pc.hpp +++ b/src/map/pc.hpp @@ -24,15 +24,9 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - #include "../generic/dumb_ptr.hpp" -#include "../mmo/utils.hpp" - -#include "../proto2/fwd.hpp" - -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" #include "map.hpp" diff --git a/src/map/script-call.cpp b/src/map/script-call.cpp index 6d3e6f2..8af5099 100644 --- a/src/map/script-call.cpp +++ b/src/map/script-call.cpp @@ -25,7 +25,8 @@ #include "../generic/intern-pool.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" + +#include "../mmo/cxxstdio_enums.hpp" #include "battle.hpp" #include "map.hpp" diff --git a/src/map/script-call.hpp b/src/map/script-call.hpp index 89cadb8..1a405b2 100644 --- a/src/map/script-call.hpp +++ b/src/map/script-call.hpp @@ -26,12 +26,6 @@ #include "../compat/borrow.hpp" -#include "../range/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../mmo/fwd.hpp" - namespace tmwa { diff --git a/src/map/script-fun.cpp b/src/map/script-fun.cpp index 958b127..69aee10 100644 --- a/src/map/script-fun.cpp +++ b/src/map/script-fun.cpp @@ -33,10 +33,11 @@ #include "../net/timer.hpp" -#include "../mmo/core.hpp" - #include "../proto2/net-HumanTimeDiff.hpp" +#include "../high/core.hpp" +#include "../high/extract_mmo.hpp" + #include "atcommand.hpp" #include "battle.hpp" #include "chrif.hpp" diff --git a/src/map/script-parse-internal.hpp b/src/map/script-parse-internal.hpp index f7e153b..89a35fd 100644 --- a/src/map/script-parse-internal.hpp +++ b/src/map/script-parse-internal.hpp @@ -23,8 +23,6 @@ #include "script-parse.hpp" #include "fwd.hpp" -#include "../compat/fwd.hpp" - #include "../strings/rstring.hpp" diff --git a/src/map/script-parse.cpp b/src/map/script-parse.cpp index e2cb4c6..7956831 100644 --- a/src/map/script-parse.cpp +++ b/src/map/script-parse.cpp @@ -30,7 +30,8 @@ #include "../strings/rstring.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" + +#include "../mmo/cxxstdio_enums.hpp" #include "map.t.hpp" #include "script-buffer.hpp" diff --git a/src/map/script-parse.hpp b/src/map/script-parse.hpp index 6f536f8..d1f824f 100644 --- a/src/map/script-parse.hpp +++ b/src/map/script-parse.hpp @@ -24,10 +24,6 @@ #include -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - namespace tmwa { diff --git a/src/map/script-startup-internal.hpp b/src/map/script-startup-internal.hpp index e4d6a8f..0b2b0e1 100644 --- a/src/map/script-startup-internal.hpp +++ b/src/map/script-startup-internal.hpp @@ -23,10 +23,6 @@ #include "script-startup.hpp" #include "fwd.hpp" -#include "../generic/fwd.hpp" - -#include "../strings/fwd.hpp" - #include "script-persist.hpp" diff --git a/src/map/script-startup.cpp b/src/map/script-startup.cpp index 27ec903..7c77a27 100644 --- a/src/map/script-startup.cpp +++ b/src/map/script-startup.cpp @@ -28,13 +28,12 @@ #include "../generic/intern-pool.hpp" #include "../io/cxxstdio.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../io/lock.hpp" #include "../net/timer.hpp" -#include "../mmo/extract.hpp" - #include "map.hpp" #include "script-parse-internal.hpp" #include "script-persist.hpp" diff --git a/src/map/script-startup.hpp b/src/map/script-startup.hpp index 8a6b50d..3894676 100644 --- a/src/map/script-startup.hpp +++ b/src/map/script-startup.hpp @@ -22,8 +22,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - namespace tmwa { void do_init_script(void); diff --git a/src/map/skill-pools.cpp b/src/map/skill-pools.cpp index 89bf426..8ed03b8 100644 --- a/src/map/skill-pools.cpp +++ b/src/map/skill-pools.cpp @@ -21,7 +21,8 @@ // along with this program. If not, see . #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" + +#include "../mmo/cxxstdio_enums.hpp" #include "battle.hpp" #include "pc.hpp" diff --git a/src/map/skill.cpp b/src/map/skill.cpp index 7c79e46..9889772 100644 --- a/src/map/skill.cpp +++ b/src/map/skill.cpp @@ -39,12 +39,12 @@ #include "../generic/random.hpp" #include "../io/cxxstdio.hpp" -#include "../io/cxxstdio_enums.hpp" +#include "../io/extract.hpp" #include "../io/read.hpp" #include "../net/timer.hpp" -#include "../mmo/extract.hpp" +#include "../mmo/cxxstdio_enums.hpp" #include "../mmo/extract_enums.hpp" #include "battle.hpp" diff --git a/src/map/skill.hpp b/src/map/skill.hpp index 5d23bae..4e6fff0 100644 --- a/src/map/skill.hpp +++ b/src/map/skill.hpp @@ -20,17 +20,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "skill.t.hpp" +#include "../mmo/skill.t.hpp" #include "fwd.hpp" #include "skill-pools.hpp" -#include "../strings/fwd.hpp" #include "../strings/rstring.hpp" #include "../strings/literal.hpp" -#include "../generic/fwd.hpp" #include "../generic/array.hpp" #include "map.hpp" diff --git a/src/map/skill.t.hpp b/src/map/skill.t.hpp deleted file mode 100644 index d0e3926..0000000 --- a/src/map/skill.t.hpp +++ /dev/null @@ -1,136 +0,0 @@ -#pragma once -// skill.t.hpp - Old-style skills. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include - -#include "../generic/enum.hpp" - - -namespace tmwa -{ -// TODO remove most of these as their corresponding SkillIDs get deleted. -enum class StatusChange : uint16_t -{ - // indices into (map_session_data).status_change - SC_SENDMAX = 256, - - // sometimes means "none", sometimes not - NEGATIVE1 = 0xffff, - - // these ones are used by clif_status_change, - // e.g. by the magic system - ZERO = 0, - ATTACK_ICON_GENERIC = 2000, - ATTACK_ICON_SHEARING = 2001, - CART = 0x0c, - CLIF_OPTION_SC_INVISIBILITY = 0x1000, - CLIF_OPTION_SC_SCRIBE = 0x1001, - - // the rest are the normal effects - SC_SLOWPOISON = 14, // item script - - SC_WEIGHT50 = 35, // ? sort of used - SC_WEIGHT90 = 36, // definitely used - SC_SPEEDPOTION0 = 37, // item script - - SC_HEALING = 70, // item script - - SC_POISON = 132, // bad; actually used - - SC_ATKPOT = 185, // item script - SC_MATKPOT = 186, // unused, but kept for parallel - -// Added for Fate's spells - SC_HIDE = 194, // Hide from `detect' magic (PCs only) - SC_SHEARED = 194, // Has been sheared (mobs only) - SC_HALT_REGENERATE = 195, // Suspend regeneration - SC_FLYING_BACKPACK = 196, // Flying backpack - SC_MBARRIER = 197, // Magical barrier, magic resistance (val1 : power (%)) - SC_HASTE = 198, // `Haste' spell (val1 : power) - SC_PHYS_SHIELD = 199, // `Protect' spell, reduce damage (val1: power) - MAX_STATUSCHANGE = 200, -}; - -enum class SkillID : uint16_t -{ - // TODO: Remove these! - NEGATIVE = 0xffff, - ZERO = 0x0000, - ONE = 0x0001, - - // Basic skills. - // These should probably be made unconditional. - NV_EMOTE = 1, // - NV_TRADE = 2, // - NV_PARTY = 3, // - - AC_OWL = 45, // Mallard's Eye - - NPC_SELFDESTRUCTION = 175, // - - NPC_POISON = 178, // - - NPC_SUMMONSLAVE = 198, // - NPC_EMOTION = 199, // - - TMW_SKILLPOOL = 339, // skill pool size - - // magic skills - TMW_MAGIC = 340, // - TMW_MAGIC_LIFE = 341, // - TMW_MAGIC_WAR = 342, // - TMW_MAGIC_TRANSMUTE = 343, // - TMW_MAGIC_NATURE = 344, // - TMW_MAGIC_ETHER = 345, // - TMW_MAGIC_DARK = 346, // - TMW_MAGIC_LIGHT = 347, // - - // focusable skills - TMW_BRAWLING = 350, // - TMW_LUCKY_COUNTER = 351, // - TMW_SPEED = 352, // - TMW_RESIST_POISON = 353, // - TMW_ASTRAL_SOUL = 354, // - TMW_RAGING = 355, // - - // Note: this value is also hard-coded in common/mmo.hpp - MAX_SKILL_DB = 474, // not 450 -}; - -namespace e -{ -enum class SkillFlags : uint16_t -{ - ZERO = 0x00, - // is a pool skill - POOL_FLAG = 0x01, - // is an active pool skill - POOL_ACTIVE = 0x02, - // pool skill has been activated (used for clif) - POOL_ACTIVATED = 0x04, -}; -ENUM_BITWISE_OPERATORS(SkillFlags) -} -using e::SkillFlags; -} // namespace tmwa diff --git a/src/map/storage.cpp b/src/map/storage.cpp index 295eff0..1a98d5b 100644 --- a/src/map/storage.cpp +++ b/src/map/storage.cpp @@ -25,7 +25,7 @@ #include "../generic/db.hpp" #include "../mmo/ids.hpp" -#include "../mmo/mmo.hpp" +#include "../high/mmo.hpp" #include "chrif.hpp" #include "clif.hpp" diff --git a/src/map/storage.hpp b/src/map/storage.hpp index 59a8858..038df7d 100644 --- a/src/map/storage.hpp +++ b/src/map/storage.hpp @@ -22,15 +22,9 @@ #include "fwd.hpp" -#include "../compat/fwd.hpp" - -#include "../generic/fwd.hpp" - -#include "../mmo/fwd.hpp" - #include "../proto2/net-Storage.hpp" -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" namespace tmwa diff --git a/src/map/tmw.cpp b/src/map/tmw.cpp index 60b5027..04906b6 100644 --- a/src/map/tmw.cpp +++ b/src/map/tmw.cpp @@ -29,7 +29,6 @@ #include "../io/cxxstdio.hpp" #include "../mmo/human_time_diff.hpp" -#include "../mmo/utils.hpp" #include "atcommand.hpp" #include "battle.hpp" diff --git a/src/map/tmw.hpp b/src/map/tmw.hpp index ffd6f7f..7f0a57e 100644 --- a/src/map/tmw.hpp +++ b/src/map/tmw.hpp @@ -21,10 +21,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - -#include "../generic/fwd.hpp" - namespace tmwa { diff --git a/src/map/trade.hpp b/src/map/trade.hpp index 91ed954..86bfc96 100644 --- a/src/map/trade.hpp +++ b/src/map/trade.hpp @@ -22,9 +22,7 @@ #include "fwd.hpp" -#include "../generic/fwd.hpp" - -#include "clif.t.hpp" +#include "../mmo/clif.t.hpp" namespace tmwa diff --git a/src/mmo/clif.t.hpp b/src/mmo/clif.t.hpp new file mode 100644 index 0000000..0a51523 --- /dev/null +++ b/src/mmo/clif.t.hpp @@ -0,0 +1,717 @@ +#pragma once +// clif.t.hpp - Network interface to the client. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include + +#include "../ints/little.hpp" + +#include "../compat/iter.hpp" + +#include "../generic/enum.hpp" + +#include "consts.hpp" +#include "enums.hpp" + + +namespace tmwa +{ +namespace e +{ +// [Fate] status.option properties. These are persistent status changes. +// IDs that are not listed are not used in the code (to the best of my knowledge) +enum class Opt0 : uint16_t +{ + ZERO = 0x0000, + + // [Fate] This is the GM `@hide' flag + HIDE = 0x0040, + // [Fate] Complete invisibility to other clients + INVISIBILITY = 0x1000, + + // ? + REAL_ANY_HIDE = HIDE, +}; +enum class Opt1 : uint16_t +{ + ZERO = 0, + _stone1 = 1, + _freeze = 2, + _stan = 3, + _sleep = 4, + _stone6 = 6, +}; +enum class Opt2 : uint16_t +{ + ZERO = 0x0000, + _poison = 0x0001, + _curse = 0x0002, + _silence = 0x0004, + BLIND = 0x0010, + _speedpotion0 = 0x0020, + _signumcrucis = 0x0040, + _atkpot = 0x0080, + _heal = 0x0100, + _slowpoison = 0x0200, +}; +enum class Opt3 : uint16_t +{ + ZERO = 0x0000, + _concentration = 0x0001, + _overthrust = 0x0002, + _energycoat = 0x0004, + _explosionspirits = 0x0008, + _steelbody = 0x0010, + _berserk = 0x0080, + + _marionette = 0x0400, + _assumptio = 0x0800, +}; + +ENUM_BITWISE_OPERATORS(Opt0) +ENUM_BITWISE_OPERATORS(Opt2) +ENUM_BITWISE_OPERATORS(Opt3) +} +using e::Opt0; +using e::Opt1; +using e::Opt2; +using e::Opt3; + + +enum class ItemType : uint8_t +{ + USE = 0, // in eA, healing only + _1 = 1, // unused + _2 = 2, // in eA, other usable items + JUNK = 3, // "useless" items (e.g. quests) + WEAPON = 4, // all weapons + ARMOR = 5, // all other equipment + _6 = 6, // in eA, card + _7 = 7, // in eA, pet egg + _8 = 8, // in eA, pet equipment + _9 = 9, // unused + ARROW = 10, // ammo + _11 = 11, // in eA, delayed use (special script) +}; + +enum class BeingRemoveWhy : uint8_t +{ + // general disappearance + GONE = 0, + // only case handled specially in client + DEAD = 1, + QUIT = 2, + WARPED = 3, + // handled specially in clif_clearchar - sent as 0 over network + DISGUISE = 9, + + // handled speciall in mob_warp - not actually sent over network + NEGATIVE1 = 0xff, +}; + +enum class PickupFail : uint8_t +{ + OKAY = 0, + BAD_ITEM = 1, + TOO_HEAVY = 2, + TOO_FAR = 3, + INV_FULL = 4, + STACK_FULL = 5, + DROP_STEAL = 6, +}; + +// this is used for both input and output +// different values are valid in 0x0089 vs 0x008a +enum class DamageType : uint8_t +{ + NORMAL = 0x00, + TAKEITEM = 0x01, + SIT = 0x02, + STAND = 0x03, + RETURNED = 0x04, + CONTINUOUS = 0x07, + DOUBLED = 0x08, + CRITICAL = 0x0a, + FLEE2 = 0x0b, +}; + +enum class LOOK : uint8_t +{ + BASE = 0, + HAIR = 1, + WEAPON = 2, + HEAD_BOTTOM = 3, + HEAD_TOP = 4, + HEAD_MID = 5, + HAIR_COLOR = 6, + CLOTHES_COLOR = 7, + SHIELD = 8, + SHOES = 9, + GLOVES = 10, + CAPE = 11, + MISC1 = 12, + MISC2 = 13, + + COUNT, +}; + +// Note: there is also a typedef by this name in +// but we should be fine since we never include it. +// (in the long term we should still rename this though) +enum class DIR : uint8_t +{ + S = 0, + SW = 1, + W = 2, + NW = 3, + N = 4, + NE = 5, + E = 6, + SE = 7, + + COUNT, +}; + +constexpr +earray dirx //= +{{ + 0, -1, -1, -1, 0, 1, 1, 1, +}}, diry //= +{{ + 1, 1, 0, -1, -1, -1, 0, 1, +}}; + +constexpr +bool dir_is_diagonal(DIR d) +{ + return static_cast(d) & 1; +} + + +enum class SP : uint16_t +{ + // sent to client + SPEED = 0, + + // when used as "no stat" + ZERO = 0, + + // sent to client + BASEEXP = 1, + // sent to client + JOBEXP = 2, +#if 0 + KARMA = 3, +#endif + + // sent to client + HP = 5, + // sent to client + MAXHP = 6, + // sent to client + SP = 7, + // sent to client + MAXSP = 8, + // sent to client + STATUSPOINT = 9, + + // sent to client + BASELEVEL = 11, + // sent to client + SKILLPOINT = 12, + // sent to client + STR = 13, + // sent to client + AGI = 14, + // sent to client + VIT = 15, + // sent to client + INT = 16, + // sent to client + DEX = 17, + // sent to client + LUK = 18, + CLASS = 19, + // sent to client + ZENY = 20, + SEX = 21, + // sent to client + NEXTBASEEXP = 22, + // sent to client + NEXTJOBEXP = 23, + // sent to client + WEIGHT = 24, + // sent to client + MAXWEIGHT = 25, + + // sent to client + USTR = 32, + // sent to client + UAGI = 33, + // sent to client + UVIT = 34, + // sent to client + UINT = 35, + // sent to client + UDEX = 36, + // sent to client + ULUK = 37, + + // sent to client + ATK1 = 41, + // sent to client + ATK2 = 42, + // sent to client + MATK1 = 43, + // sent to client + MATK2 = 44, + // sent to client + DEF1 = 45, + // sent to client + DEF2 = 46, + // sent to client + MDEF1 = 47, + // sent to client + MDEF2 = 48, + // sent to client + HIT = 49, + // sent to client + FLEE1 = 50, + // sent to client + FLEE2 = 51, + // sent to client + CRITICAL = 52, + // sent to client + ASPD = 53, + + // sent to client + JOBLEVEL = 55, + +#if 0 + PARTNER = 57, + CART = 58, + FAME = 59, + UNBREAKABLE = 60, +#endif + + DEAF = 70, + + // sent to client + GM = 500, + + // sent to client + ATTACKRANGE = 1000, +#if 0 + ATKELE = 1001, +#endif +#if 0 + DEFELE = 1002, +#endif +#if 0 + CASTRATE = 1003, +#endif + MAXHPRATE = 1004, +#if 0 + MAXSPRATE = 1005, +#endif +#if 0 + SPRATE = 1006, +#endif + +#if 0 + ADDEFF = 1012, +#endif +#if 0 + RESEFF = 1013, +#endif + BASE_ATK = 1014, + ASPD_RATE = 1015, + HP_RECOV_RATE = 1016, +#if 0 + SP_RECOV_RATE = 1017, +#endif +#if 0 + SPEED_RATE = 1018, +#endif + CRITICAL_DEF = 1019, +#if 0 + NEAR_ATK_DEF = 1020, +#endif +#if 0 + LONG_ATK_DEF = 1021, +#endif +#if 0 + DOUBLE_RATE = 1022, +#endif + DOUBLE_ADD_RATE = 1023, +#if 0 + MATK = 1024, +#endif +#if 0 + MATK_RATE = 1025, +#endif +#if 0 + IGNORE_DEF_ELE = 1026, +#endif +#if 0 + IGNORE_DEF_RACE = 1027, +#endif +#if 0 + ATK_RATE = 1028, +#endif + SPEED_ADDRATE = 1029, +#if 0 + ASPD_ADDRATE = 1030, +#endif +#if 0 + MAGIC_ATK_DEF = 1031, +#endif +#if 0 + MISC_ATK_DEF = 1032, +#endif +#if 0 + IGNORE_MDEF_ELE = 1033, +#endif +#if 0 + IGNORE_MDEF_RACE = 1034, +#endif + +#if 0 + PERFECT_HIT_RATE = 1038, +#endif +#if 0 + PERFECT_HIT_ADD_RATE = 1039, +#endif +#if 0 + CRITICAL_RATE = 1040, +#endif +#if 0 + GET_ZENY_NUM = 1041, +#endif +#if 0 + ADD_GET_ZENY_NUM = 1042, +#endif + +#if 0 + ADD_MONSTER_DROP_ITEM = 1047, +#endif +#if 0 + DEF_RATIO_ATK_ELE = 1048, +#endif +#if 0 + DEF_RATIO_ATK_RACE = 1049, +#endif +#if 0 + ADD_SPEED = 1050, +#endif +#if 0 + HIT_RATE = 1051, +#endif +#if 0 + FLEE_RATE = 1052, +#endif +#if 0 + FLEE2_RATE = 1053, +#endif + DEF_RATE = 1054, + DEF2_RATE = 1055, +#if 0 + MDEF_RATE = 1056, +#endif +#if 0 + MDEF2_RATE = 1057, +#endif +#if 0 + SPLASH_RANGE = 1058, +#endif +#if 0 + SPLASH_ADD_RANGE = 1059, +#endif + + HP_DRAIN_RATE = 1061, +#if 0 + SP_DRAIN_RATE = 1062, +#endif +#if 0 + SHORT_WEAPON_DAMAGE_RETURN = 1063, +#endif +#if 0 + LONG_WEAPON_DAMAGE_RETURN = 1064, +#endif + +#if 0 + ADDEFF2 = 1067, +#endif + BREAK_WEAPON_RATE = 1068, + BREAK_ARMOR_RATE = 1069, + ADD_STEAL_RATE = 1070, + MAGIC_DAMAGE_RETURN = 1071, +#if 0 + RANDOM_ATTACK_INCREASE = 1072, +#endif +}; + +constexpr +SP attr_to_sp(ATTR attr) +{ + return static_cast(static_cast(attr) + static_cast(SP::STR)); +} + +constexpr +ATTR sp_to_attr(SP sp) +{ + return static_cast(static_cast(sp) - static_cast(SP::STR)); +} + +constexpr +SP attr_to_usp(ATTR attr) +{ + return static_cast(static_cast(attr) + static_cast(SP::USTR)); +} + +constexpr +ATTR usp_to_attr(SP sp) +{ + return static_cast(static_cast(sp) - static_cast(SP::USTR)); +} + +constexpr +SP sp_to_usp(SP sp) +{ + return attr_to_usp(sp_to_attr(sp)); +} + +constexpr +SP usp_to_sp(SP sp) +{ + return attr_to_sp(usp_to_attr(sp)); +} + + +// xxxx xxxx xxyy yyyy yyyy dddd +struct NetPosition1 +{ + Byte data[3]; +}; + +struct Position1 +{ + uint16_t x, y; + DIR dir; +}; + +inline +bool native_to_network(NetPosition1 *network, Position1 native) +{ + uint16_t x = native.x; + uint16_t y = native.y; + uint8_t d = static_cast(native.dir); + + uint8_t *p = reinterpret_cast(network); + p[0] = x >> 2; + p[1] = (x << 6) | ((y >> 4) & 0x3f); + p[2] = y << 4 | d; + + return x < 1024 && y < 1024 && d < 16; +} + +inline +bool network_to_native(Position1 *native, NetPosition1 network) +{ + const uint8_t *p = reinterpret_cast(&network); + native->x = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); + native->y = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); + uint8_t d = p[2] & 0x0f; + native->dir = static_cast(d); + return d < 8; +} + +// x0xx xxxx xxy0 yyyy yyyy x1xx xxxx xxy1 yyyy yyyy +struct NetPosition2 +{ + Byte data[5]; +}; + +struct Position2 +{ + uint16_t x0, y0; + uint16_t x1, y1; +}; + +inline +bool native_to_network(NetPosition2 *network, Position2 native) +{ + uint16_t x0 = native.x0; + uint16_t y0 = native.y0; + uint16_t x1 = native.x1; + uint16_t y1 = native.y1; + + uint8_t *p = reinterpret_cast(network); + p[0] = x0 >> 2; + p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f); + p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f); + p[3] = (x1 << 2) | ((y1 >> 8) & 0x03); + p[4] = y1; + + return x0 < 1024 && y0 < 1024 && x1 < 1024 && y1 < 1024; +} + +inline +bool network_to_native(Position2 *native, NetPosition2 network) +{ + const uint8_t *p = reinterpret_cast(&network); + native->x0 = (p[0] & (0x3ff >> 2)) << 2 | p[1] >> (8 - 2); + native->y0 = (p[1] & (0x3ff >> 4)) << 4 | p[2] >> (8 - 4); + native->x1 = (p[2] & (0x3ff >> 6)) << 6 | p[3] >> (8 - 6); + native->y1 = (p[3] & (0x3ff >> 8)) << 8 | p[4] >> (8 - 8); + return true; +} + +struct IOff2; +struct SOff1; + +struct IOff0 +{ + uint16_t index; + + bool ok() const + { return get0() < MAX_INVENTORY; } + uint16_t get0() const + { return index; } + static IOff0 from(uint16_t i) + { return IOff0{i}; } + static IteratorPair> iter() + { return {IOff0::from(0), IOff0::from(MAX_INVENTORY)}; } + friend uint16_t convert_for_printf(IOff0 i0) { return i0.index; } + + IOff0& operator ++() { ++index; return *this; } + friend bool operator == (IOff0 l, IOff0 r) { return l.index == r.index; } + friend bool operator != (IOff0 l, IOff0 r) { return !(l == r); } + IOff2 shift() const; + + IOff0() : index(0) {} +private: + explicit IOff0(uint16_t i) : index(i) {} +}; + +struct SOff0 +{ + uint16_t index; + + bool ok() const + { return get0() < MAX_STORAGE; } + uint16_t get0() const + { return index; } + static SOff0 from(uint16_t i) + { return SOff0{i}; } + static IteratorPair> iter() + { return {SOff0::from(0), SOff0::from(MAX_STORAGE)}; } + friend uint16_t convert_for_printf(SOff0 s0) { return s0.index; } + + SOff0& operator ++() { ++index; return *this; } + friend bool operator == (SOff0 l, SOff0 r) { return l.index == r.index; } + friend bool operator != (SOff0 l, SOff0 r) { return !(l == r); } + SOff1 shift() const; + + SOff0() : index(0) {} +private: + explicit SOff0(uint16_t i) : index(i) {} +}; + +struct IOff2 +{ + uint16_t index; + + bool ok() const + { return get2() < MAX_INVENTORY; } + uint16_t get2() const + { return index - 2; } + static IOff2 from(uint16_t i) + { return IOff2{static_cast(i + 2)}; } + static IteratorPair> iter() + { return {IOff2::from(0), IOff2::from(MAX_INVENTORY)}; } + + IOff2& operator ++() { ++index; return *this; } + friend bool operator == (IOff2 l, IOff2 r) { return l.index == r.index; } + friend bool operator != (IOff2 l, IOff2 r) { return !(l == r); } + IOff0 unshift() const + { return IOff0::from(get2()); } + + IOff2() : index(0) {} +private: + explicit IOff2(uint16_t i) : index(i) {} +}; + +struct SOff1 +{ + uint16_t index; + + bool ok() const + { return get1() < MAX_STORAGE; } + uint16_t get1() const + { return index - 1; } + static SOff1 from(uint16_t i) + { return SOff1{static_cast(i + 1)}; } + static IteratorPair> iter() + { return {SOff1::from(0), SOff1::from(MAX_STORAGE)}; } + + SOff1& operator ++() { ++index; return *this; } + friend bool operator == (SOff1 l, SOff1 r) { return l.index == r.index; } + friend bool operator != (SOff1 l, SOff1 r) { return !(l == r); } + SOff0 unshift() const + { return SOff0::from(get1()); } + + SOff1() : index(0) {} +private: + explicit SOff1(uint16_t i) : index(i) {} +}; + +inline IOff2 IOff0::shift() const +{ return IOff2::from(get0()); } +inline SOff1 SOff0::shift() const +{ return SOff1::from(get0()); } + +inline +bool native_to_network(Little16 *network, IOff2 native) +{ + return native_to_network(network, native.index); +} + +inline +bool network_to_native(IOff2 *native, Little16 network) +{ + return network_to_native(&native->index, network); +} + +inline +bool native_to_network(Little16 *network, SOff1 native) +{ + return native_to_network(network, native.index); +} + +inline +bool network_to_native(SOff1 *native, Little16 network) +{ + return network_to_native(&native->index, network); +} +} // namespace tmwa diff --git a/src/mmo/config_parse.hpp b/src/mmo/config_parse.hpp index 50a115e..db097e9 100644 --- a/src/mmo/config_parse.hpp +++ b/src/mmo/config_parse.hpp @@ -20,8 +20,6 @@ #include "fwd.hpp" -#include "../strings/fwd.hpp" - namespace tmwa { diff --git a/src/mmo/core.cpp b/src/mmo/core.cpp deleted file mode 100644 index ff12f17..0000000 --- a/src/mmo/core.cpp +++ /dev/null @@ -1,161 +0,0 @@ -#include "core.hpp" -// core.cpp - The main loop. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include - -#include - -#include -#include - -#include - -#include "../strings/zstring.hpp" -#include "../strings/literal.hpp" - -#include "../io/cxxstdio.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. -// (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced -// Programming in the UNIX Environment_. -// -typedef void(*sigfunc)(int); -static -sigfunc compat_signal(int signo, sigfunc func) -{ - struct sigaction sact, oact; - - sact.sa_handler = func; - sigfillset(&sact.sa_mask); - sigdelset(&sact.sa_mask, SIGSEGV); - sigdelset(&sact.sa_mask, SIGBUS); - sigdelset(&sact.sa_mask, SIGTRAP); - sigdelset(&sact.sa_mask, SIGILL); - sigdelset(&sact.sa_mask, SIGFPE); - sact.sa_flags = 0; - - if (sigaction(signo, &sact, &oact) < 0) - { - DIAG_PUSH(); - DIAG_I(old_style_cast); - return SIG_ERR; - DIAG_POP(); - } - - return oact.sa_handler; -} - -volatile -bool runflag = true; - -static -void chld_proc(int) -{ - wait(nullptr); -} -static -void sig_proc(int) -{ - for (int i = 1; i < 31; ++i) - { - DIAG_PUSH(); - DIAG_I(old_style_cast); - compat_signal(i, SIG_IGN); - DIAG_POP(); - } - runflag = false; -} - -/* - Note about fatal signals: - - Under certain circumstances, - the following signals MUST not be ignored: - SIGFPE, SIGSEGV, SIGILL - Unless you use SA_SIGINFO and *carefully* check the origin, - that means they must be SIG_DFL. - */ -} // namespace tmwa - -int tmwa_main(int argc, char **argv) -{ - using namespace tmwa; - - check_paths(); - - // ZString args[argc]; is (deliberately!) not supported by clang yet - ZString *args = static_cast(alloca(argc * sizeof(ZString))); - for (int i = 0; i < argc; ++i) - args[i] = ZString(strings::really_construct_from_a_pointer, argv[i], nullptr); - do_init(Slice(args, argc)); - - if (!runflag) - { - 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. - - DIAG_PUSH(); - DIAG_I(old_style_cast); - compat_signal(SIGPIPE, SIG_IGN); - 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) - 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); - DIAG_POP(); - - atexit(term_func); - - while (runflag) - { - // TODO - if timers take a long time to run, this - // may wait too long in sendrecv - tick_t now = milli_clock::now(); - interval_t next = do_timer(now); - do_sendrecv(next); - do_parsepacket(); - } - - return 0; -} diff --git a/src/mmo/core.hpp b/src/mmo/core.hpp deleted file mode 100644 index 259dd90..0000000 --- a/src/mmo/core.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#pragma once -// core.hpp - The main loop. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include "../range/slice.hpp" - -#include "../strings/fwd.hpp" - - -namespace tmwa -{ -/// core.c contains a server-independent main() function -/// and then runs a do_sendrecv loop - -/// When this is cleared, the server exits gracefully. -extern volatile bool runflag; - -/// This is an external function defined by each server -/// This function must register stuff for the parse loop -extern int do_init(Slice); - -/// Cleanup function called whenever a signal kills us -/// or when if we manage to exit() gracefully. -extern void term_func(void); -} // namespace tmwa - -/// grumble grumble stupid intertwined includes mumble mumble -__attribute__((warn_unused_result)) -extern int tmwa_main(int argc, char **argv); diff --git a/src/mmo/cxxstdio_enums.hpp b/src/mmo/cxxstdio_enums.hpp new file mode 100644 index 0000000..6f428e8 --- /dev/null +++ b/src/mmo/cxxstdio_enums.hpp @@ -0,0 +1,77 @@ +#pragma once +// cxxstdio_enums.hpp - Opt-in integer formatting support for enums. +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +namespace e +{ +enum class BF : uint16_t; +enum class EPOS : uint16_t; +enum class MapCell : uint8_t; +enum class Opt0 : uint16_t; + +inline +auto decay_for_printf(BF v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(EPOS v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(MapCell v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(Opt0 v) -> typename remove_enum::type { return typename remove_enum::type(v); } +} + +namespace magic +{ +enum class SPELLARG : uint8_t; + +inline +auto decay_for_printf(SPELLARG v) -> typename remove_enum::type { return typename remove_enum::type(v); } +} + +enum class BL : uint8_t; +enum class ByteCode : uint8_t; +enum class ItemLook : uint16_t; +enum class MS : uint8_t; +enum class SP : uint16_t; +enum class SkillID : uint16_t; +enum class StatusChange : uint16_t; + +inline +auto decay_for_printf(BL v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(ByteCode v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(ItemLook v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(MS v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(SP v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(SkillID v) -> typename remove_enum::type { return typename remove_enum::type(v); } +inline +auto decay_for_printf(StatusChange v) -> typename remove_enum::type { return typename remove_enum::type(v); } +} // namespace tmwa diff --git a/src/mmo/extract.cpp b/src/mmo/extract.cpp deleted file mode 100644 index 9123237..0000000 --- a/src/mmo/extract.cpp +++ /dev/null @@ -1,280 +0,0 @@ -#include "extract.hpp" -// extract.cpp - a simple, hierarchical, tokenizer -// -// Copyright © 2013 Ben Longbons -// -// 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 . - -#include - -#include "../strings/astring.hpp" -#include "../strings/xstring.hpp" -#include "../strings/vstring.hpp" - -#include "extract_enums.hpp" -#include "mmo.hpp" - -#include "../poison.hpp" - - -// TODO move this whole file to io/ or something. -// It needs to be lower in the include hierarchy so it can be implemented -// for library types. Also it should pass an io::LineSpan around. -namespace tmwa -{ -bool extract(XString str, XString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, RString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, AString *rv) -{ - *rv = str; - return true; -} - -bool extract(XString str, GlobalReg *var) -{ - return extract(str, - record<','>(&var->str, &var->value)); -} - -bool extract(XString str, Item *it) -{ - XString ignored; - XString corruption_hack_amount; - bool rv = extract(str, - record<',', 11>( - &ignored, - &it->nameid, - &corruption_hack_amount, - &it->equip, - &ignored, - &ignored, - &ignored, - &ignored, - &ignored, - &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; -} - -bool extract(XString str, std::chrono::nanoseconds *ns) -{ - std::chrono::nanoseconds::rep rep; - if (extract(str, &rep)) - { - *ns = std::chrono::nanoseconds(rep); - return true; - } - if (str.endswith("ns"_s)) - { - if (extract(str.xrslice_h("ns"_s.size()), &rep)) - { - *ns = std::chrono::nanoseconds(rep); - return true; - } - return false; - } - std::chrono::microseconds bigger; - if (extract(str, &bigger)) - { - *ns = bigger; - return *ns == bigger; - } - return false; -} -bool extract(XString str, std::chrono::microseconds *us) -{ - std::chrono::microseconds::rep rep; - if (extract(str, &rep)) - { - *us = std::chrono::microseconds(rep); - return true; - } - if (str.endswith("us"_s)) - { - if (extract(str.xrslice_h("us"_s.size()), &rep)) - { - *us = std::chrono::microseconds(rep); - return true; - } - return false; - } - std::chrono::milliseconds bigger; - if (extract(str, &bigger)) - { - *us = bigger; - return *us == bigger; - } - return false; -} -bool extract(XString str, std::chrono::milliseconds *ms) -{ - std::chrono::milliseconds::rep rep; - if (extract(str, &rep)) - { - *ms = std::chrono::milliseconds(rep); - return true; - } - if (str.endswith("ms"_s)) - { - if (extract(str.xrslice_h("ms"_s.size()), &rep)) - { - *ms = std::chrono::milliseconds(rep); - return true; - } - return false; - } - std::chrono::seconds bigger; - if (extract(str, &bigger)) - { - *ms = bigger; - return *ms == bigger; - } - return false; -} -bool extract(XString str, std::chrono::seconds *s) -{ - std::chrono::seconds::rep rep; - if (extract(str, &rep)) - { - *s = std::chrono::seconds(rep); - return true; - } - if (str.endswith("s"_s)) - { - if (extract(str.xrslice_h("s"_s.size()), &rep)) - { - *s = std::chrono::seconds(rep); - return true; - } - return false; - } - std::chrono::minutes bigger; - if (extract(str, &bigger)) - { - *s = bigger; - return *s == bigger; - } - return false; -} -bool extract(XString str, std::chrono::minutes *min) -{ - std::chrono::minutes::rep rep; - if (extract(str, &rep)) - { - *min = std::chrono::minutes(rep); - return true; - } - if (str.endswith("min"_s)) - { - if (extract(str.xrslice_h("min"_s.size()), &rep)) - { - *min = std::chrono::minutes(rep); - return true; - } - return false; - } - std::chrono::hours bigger; - if (extract(str, &bigger)) - { - *min = bigger; - return *min == bigger; - } - return false; -} -bool extract(XString str, std::chrono::hours *h) -{ - std::chrono::hours::rep rep; - if (extract(str, &rep)) - { - *h = std::chrono::hours(rep); - return true; - } - if (str.endswith("h"_s)) - { - if (extract(str.xrslice_h("h"_s.size()), &rep)) - { - *h = std::chrono::hours(rep); - return true; - } - return false; - } - std::chrono::duration> bigger; - if (extract(str, &bigger)) - { - *h = bigger; - return *h == bigger; - } - return false; -} -bool extract(XString str, std::chrono::duration> *d) -{ - std::chrono::duration>::rep rep; - if (extract(str, &rep)) - { - *d = std::chrono::duration>(rep); - return true; - } - if (str.endswith("d"_s)) - { - if (extract(str.xrslice_h("d"_s.size()), &rep)) - { - *d = std::chrono::duration>(rep); - return true; - } - return false; - } - return false; -} -} // namespace tmwa diff --git a/src/mmo/extract.hpp b/src/mmo/extract.hpp deleted file mode 100644 index 152d1b7..0000000 --- a/src/mmo/extract.hpp +++ /dev/null @@ -1,240 +0,0 @@ -#pragma once -// extract.hpp - a simple, hierarchical, tokenizer -// -// Copyright © 2012-2013 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include -#include - -#include -#include -#include - -#include "../ints/wrap.hpp" - -#include "../strings/xstring.hpp" - -#include "../generic/enum.hpp" - -#include "utils.hpp" - - -namespace tmwa -{ -template -bool do_extract(XString str, T t); - -template::value && !std::is_same::value && !std::is_same::value>::type> -bool extract(XString str, T *iv) -{ - if (!str || str.size() > 20) - return false; - if (!((str.front() == '-' && std::is_signed::value) - || ('0' <= str.front() && str.front() <= '9'))) - return false; - // needs a NUL, but can't always be given one. TODO VString? - char buf[20 + 1]; - std::copy(str.begin(), str.end(), buf); - buf[str.size()] = '\0'; - - char *end; - errno = 0; - if (std::is_signed::value) - { - long long v = strtoll(buf, &end, 10); - if (errno || *end) - return false; - *iv = v; - return *iv == v; - } - else - { - unsigned long long v = strtoull(buf, &end, 10); - if (errno || *end) - return false; - *iv = v; - return *iv == v; - } -} - -inline -bool extract(XString str, TimeT *tv) -{ - return extract(str, &tv->value); -} - -template::value>::type> -bool extract_as_int(XString str, T *iv) -{ - typedef typename underlying_type::type U; - U v; - // defer to integer version - if (!extract(str, &v)) - return false; - // TODO check bounds using enum min/max as in SSCANF - *iv = static_cast(v); - return true; -} - -bool extract(XString str, XString *rv); -bool extract(XString str, RString *rv); -bool extract(XString str, AString *rv); - -template -bool extract(XString str, VString *out) -{ - if (str.size() > N) - return false; - *out = str; - return true; -} - -inline -bool extract(XString str, LString exact) -{ - return str == exact; -} - -template -class LStripper -{ -public: - T impl; -}; - -template -LStripper lstripping(T v) -{ - return {v}; -} - -template -bool extract(XString str, LStripper out) -{ - return extract(str.lstrip(), out.impl); -} - -// basically just a std::tuple -// but it provides its data members publically -template -class Record; -template -class Record -{ -}; -template -class Record -{ -public: - F frist; - Record rest; -public: - Record(F f, R... r) - : frist(f), rest(r...) - {} -}; -template -Record record(T... t) -{ - return Record(t...); -} -template -Record record(T... t) -{ - static_assert(0 < n && n < sizeof...(T), "don't be silly"); - return Record(t...); -} - -template -bool extract(XString str, Record) -{ - return !str; -} - -template -bool extract(XString str, Record rec) -{ - XString::iterator s = std::find(str.begin(), str.end(), split); - XString::iterator s2 = s; - if (s2 != str.end()) - ++s2; - XString head = str.xislice_h(s); - XString tail = str.xislice_t(s2); - if (s == str.end()) - return (extract(head, rec.frist) && n <= 1) - || (!head && n <= 0); - - return (extract(head, rec.frist) || n <= 0) - && extract(tail, rec.rest); -} - -template -struct VRecord -{ - std::vector *arr; -}; - -template -VRecord vrec(std::vector *arr) -{ - return {arr}; -} - -template -bool extract(XString str, VRecord rec) -{ - if (!str) - return true; - XString::iterator s = std::find(str.begin(), str.end(), split); - rec.arr->emplace_back(); - if (s == str.end()) - return extract(str, &rec.arr->back()); - return extract(str.xislice_h(s), &rec.arr->back()) - && extract(str.xislice_t(s + 1), rec); -} - -bool extract(XString str, GlobalReg *var); - -bool extract(XString str, Item *it); - -bool extract(XString str, MapName *m); - -bool extract(XString str, CharName *out); - -template -bool do_extract(XString str, T t) -{ - return extract(str, t); -} - -template -bool extract(XString str, Wrapped *w) -{ - return extract(str, &w->_value); -} - -bool extract(XString str, std::chrono::nanoseconds *ns); -bool extract(XString str, std::chrono::microseconds *us); -bool extract(XString str, std::chrono::milliseconds *ms); -bool extract(XString str, std::chrono::seconds *s); -bool extract(XString str, std::chrono::minutes *min); -bool extract(XString str, std::chrono::hours *h); -bool extract(XString str, std::chrono::duration> *d); -} // namespace tmwa diff --git a/src/mmo/extract_enums.cpp b/src/mmo/extract_enums.cpp new file mode 100644 index 0000000..ecf6940 --- /dev/null +++ b/src/mmo/extract_enums.cpp @@ -0,0 +1,59 @@ +#include "extract_enums.hpp" +// extract_enums.cpp - Opt-in integer extraction support for enums. +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "../poison.hpp" + + +namespace tmwa +{ +bool extract(XString str, DIR *d) +{ + unsigned di; + if (extract(str, &di) && di < 8) + { + *d = static_cast(di); + return true; + } + const struct + { + LString str; + DIR d; + } dirs[] = + { + {"S"_s, DIR::S}, + {"SW"_s, DIR::SW}, + {"W"_s, DIR::W}, + {"NW"_s, DIR::NW}, + {"N"_s, DIR::N}, + {"NE"_s, DIR::NE}, + {"E"_s, DIR::E}, + {"SE"_s, DIR::SE}, + }; + for (auto& pair : dirs) + { + if (str == pair.str) + { + *d = pair.d; + return true; + } + } + return false; +} +} // namespace tmwa diff --git a/src/mmo/extract_enums.hpp b/src/mmo/extract_enums.hpp index 60ad493..96e5df7 100644 --- a/src/mmo/extract_enums.hpp +++ b/src/mmo/extract_enums.hpp @@ -22,7 +22,9 @@ #include -#include "extract.hpp" +#include "../io/extract.hpp" + +#include "clif.t.hpp" namespace tmwa @@ -66,4 +68,6 @@ inline bool extract(XString str, SkillID *iv) { return extract_as_int(str, iv); } inline bool extract(XString str, StatusChange *iv) { return extract_as_int(str, iv); } + +bool extract(XString, DIR *); } // namespace tmwa diff --git a/src/mmo/extract_test.cpp b/src/mmo/extract_test.cpp deleted file mode 100644 index 9c203ac..0000000 --- a/src/mmo/extract_test.cpp +++ /dev/null @@ -1,448 +0,0 @@ -#include "extract.hpp" -// extract_test.cpp - Testsuite for a simple, hierarchical, tokenizer -// -// Copyright © 2013 Ben Longbons -// -// 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 . - -#include - -#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 "_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"_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 "_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"_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 "_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"_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 "_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"_s, record<' '>(&x, &y, &z))); - EXPECT_EQ(1, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; - 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(""_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 "_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"_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 "_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"_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 "_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"_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 "_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"_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(" "_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(""_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 "_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"_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 "_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"_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 "_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"_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 "_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"_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(" "_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(""_s, record<' ', 1>(&x, &y, &z))); - EXPECT_EQ(0, x); - EXPECT_EQ(0, y); - EXPECT_EQ(0, z); - x = y = z = 0; -} - -TEST(extract, record_str) -{ - XString 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 "_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 "_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"_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); -} - -TEST(extract, chrono) -{ - std::chrono::nanoseconds ns; - std::chrono::microseconds us; - std::chrono::milliseconds ms; - std::chrono::seconds s; - std::chrono::minutes min; - std::chrono::hours h; - std::chrono::duration> d; - - EXPECT_TRUE(extract("1"_s, &ns)); - EXPECT_EQ(ns, 1_ns); - EXPECT_TRUE(extract("3ns"_s, &ns)); - EXPECT_EQ(ns, 3_ns); - EXPECT_TRUE(extract("4us"_s, &ns)); - EXPECT_EQ(ns, 4_us); - EXPECT_TRUE(extract("5ms"_s, &ns)); - EXPECT_EQ(ns, 5_ms); - EXPECT_TRUE(extract("6s"_s, &ns)); - EXPECT_EQ(ns, 6_s); - EXPECT_TRUE(extract("7min"_s, &ns)); - EXPECT_EQ(ns, 7_min); - EXPECT_TRUE(extract("8h"_s, &ns)); - EXPECT_EQ(ns, 8_h); - EXPECT_TRUE(extract("9d"_s, &ns)); - EXPECT_EQ(ns, 9_d); - - EXPECT_TRUE(extract("1"_s, &us)); - EXPECT_EQ(us, 1_us); - EXPECT_TRUE(extract("4us"_s, &us)); - EXPECT_EQ(us, 4_us); - EXPECT_TRUE(extract("5ms"_s, &us)); - EXPECT_EQ(us, 5_ms); - EXPECT_TRUE(extract("6s"_s, &us)); - EXPECT_EQ(us, 6_s); - EXPECT_TRUE(extract("7min"_s, &us)); - EXPECT_EQ(us, 7_min); - EXPECT_TRUE(extract("8h"_s, &us)); - EXPECT_EQ(us, 8_h); - EXPECT_TRUE(extract("9d"_s, &us)); - EXPECT_EQ(us, 9_d); - - EXPECT_TRUE(extract("1"_s, &ms)); - EXPECT_EQ(ms, 1_ms); - EXPECT_TRUE(extract("5ms"_s, &ms)); - EXPECT_EQ(ms, 5_ms); - EXPECT_TRUE(extract("6s"_s, &ms)); - EXPECT_EQ(ms, 6_s); - EXPECT_TRUE(extract("7min"_s, &ms)); - EXPECT_EQ(ms, 7_min); - EXPECT_TRUE(extract("8h"_s, &ms)); - EXPECT_EQ(ms, 8_h); - EXPECT_TRUE(extract("9d"_s, &ms)); - EXPECT_EQ(ms, 9_d); - - EXPECT_TRUE(extract("1"_s, &s)); - EXPECT_EQ(s, 1_s); - EXPECT_TRUE(extract("6s"_s, &s)); - EXPECT_EQ(s, 6_s); - EXPECT_TRUE(extract("7min"_s, &s)); - EXPECT_EQ(s, 7_min); - EXPECT_TRUE(extract("8h"_s, &s)); - EXPECT_EQ(s, 8_h); - EXPECT_TRUE(extract("9d"_s, &s)); - EXPECT_EQ(s, 9_d); - - EXPECT_TRUE(extract("1"_s, &min)); - EXPECT_EQ(min, 1_min); - EXPECT_TRUE(extract("7min"_s, &min)); - EXPECT_EQ(min, 7_min); - EXPECT_TRUE(extract("8h"_s, &min)); - EXPECT_EQ(min, 8_h); - EXPECT_TRUE(extract("9d"_s, &min)); - EXPECT_EQ(min, 9_d); - - EXPECT_TRUE(extract("1"_s, &h)); - EXPECT_EQ(h, 1_h); - EXPECT_TRUE(extract("8h"_s, &h)); - EXPECT_EQ(h, 8_h); - EXPECT_TRUE(extract("9d"_s, &h)); - EXPECT_EQ(h, 9_d); - - EXPECT_TRUE(extract("1"_s, &d)); - EXPECT_EQ(d, 1_d); - EXPECT_TRUE(extract("9d"_s, &d)); - EXPECT_EQ(d, 9_d); -} -} // namespace tmwa diff --git a/src/mmo/fwd.hpp b/src/mmo/fwd.hpp index 6612aab..f51767d 100644 --- a/src/mmo/fwd.hpp +++ b/src/mmo/fwd.hpp @@ -20,13 +20,20 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +// mmo/fwd.hpp is rank 6 + namespace tmwa { // meh, add more when I feel like it class MapName; class CharName; -class CharPair; class HumanTimeDiff; @@ -48,22 +55,9 @@ 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; +struct MobName; +struct NpcName; +struct ScriptLabel; +struct ItemName; +struct NpcEvent; } // namespace tmwa diff --git a/src/mmo/human_time_diff.cpp b/src/mmo/human_time_diff.cpp new file mode 100644 index 0000000..e434773 --- /dev/null +++ b/src/mmo/human_time_diff.cpp @@ -0,0 +1,68 @@ +#include "human_time_diff.hpp" +// human_time_diff.cpp - broken deltas +// +// Copyright © 2013 Ben Longbons +// +// 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 . + +#include "../io/extract.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +bool extract(XString str, HumanTimeDiff *iv) +{ + // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) + // there are NO spaces here + // parse by counting the number starts + auto is_num = [](char c) + { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; + if (!str || !is_num(str.front())) + return false; + *iv = HumanTimeDiff{}; + while (str) + { + auto it = std::find_if_not(str.begin(), str.end(), is_num); + auto it2 = std::find_if(it, str.end(), is_num); + XString number = str.xislice_h(it); + XString suffix = str.xislice(it, it2); + str = str.xislice_t(it2); + + short *ptr = nullptr; + if (suffix == "y"_s || suffix == "a"_s) + ptr = &iv->year; + else if (suffix == "m"_s) + ptr = &iv->month; + else if (suffix == "j"_s || suffix == "d"_s) + ptr = &iv->day; + else if (suffix == "h"_s) + ptr = &iv->hour; + else if (suffix == "mn"_s) + ptr = &iv->minute; + else if (suffix == "s"_s) + ptr = &iv->second; + else + return false; + if (number.startswith('+') && !number.startswith("+-"_s)) + number = number.xslice_t(1); + if (*ptr || !extract(number, ptr)) + return false; + } + return true; +} +} // namespace tmwa diff --git a/src/mmo/human_time_diff.hpp b/src/mmo/human_time_diff.hpp index b5c19fb..40352d0 100644 --- a/src/mmo/human_time_diff.hpp +++ b/src/mmo/human_time_diff.hpp @@ -24,8 +24,6 @@ #include "../strings/xstring.hpp" -#include "extract.hpp" - namespace tmwa { @@ -44,46 +42,5 @@ struct HumanTimeDiff return !bool(*this); } }; - -inline -bool extract(XString str, HumanTimeDiff *iv) -{ - // str is a sequence of [-+]?[0-9]+([ay]|m|[jd]|h|mn|s) - // there are NO spaces here - // parse by counting the number starts - auto is_num = [](char c) - { return c == '-' || c == '+' || ('0' <= c && c <= '9'); }; - if (!str || !is_num(str.front())) - return false; - *iv = HumanTimeDiff{}; - while (str) - { - auto it = std::find_if_not(str.begin(), str.end(), is_num); - auto it2 = std::find_if(it, str.end(), is_num); - XString number = str.xislice_h(it); - XString suffix = str.xislice(it, it2); - str = str.xislice_t(it2); - - short *ptr = nullptr; - if (suffix == "y"_s || suffix == "a"_s) - ptr = &iv->year; - else if (suffix == "m"_s) - ptr = &iv->month; - else if (suffix == "j"_s || suffix == "d"_s) - ptr = &iv->day; - else if (suffix == "h"_s) - ptr = &iv->hour; - else if (suffix == "mn"_s) - ptr = &iv->minute; - else if (suffix == "s"_s) - ptr = &iv->second; - else - return false; - if (number.startswith('+') && !number.startswith("+-"_s)) - number = number.xslice_t(1); - if (*ptr || !extract(number, ptr)) - return false; - } - return true; -} +bool extract(XString str, HumanTimeDiff *iv); } // namespace tmwa diff --git a/src/mmo/ids.cpp b/src/mmo/ids.cpp new file mode 100644 index 0000000..9c013ba --- /dev/null +++ b/src/mmo/ids.cpp @@ -0,0 +1,42 @@ +#include "ids.hpp" +// ids.cpp - special integer classes for various object IDs +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "../io/extract.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +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); +} +bool extract(XString str, GmLevel *lvl) +{ + return extract(str, &lvl->bits); +} +} // namespace tmwa diff --git a/src/mmo/ids.hpp b/src/mmo/ids.hpp index 4e2b97c..389f9e9 100644 --- a/src/mmo/ids.hpp +++ b/src/mmo/ids.hpp @@ -23,8 +23,6 @@ #include "../ints/little.hpp" #include "../ints/wrap.hpp" -#include "extract.hpp" - namespace tmwa { @@ -32,17 +30,7 @@ class Species : public Wrapped { public: explicit operator bool() cons 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); -} +bool extract(XString str, Species *w); class AccountId : public Wrapped { public: constexpr AccountId() : Wrapped() {} protected: constexpr explicit AccountId(uint32_t a) : Wrapped(a) {} }; @@ -53,11 +41,12 @@ class ItemNameId : public Wrapped { public: constexpr ItemNameId() : W class BlockId : public Wrapped { public: constexpr BlockId() : Wrapped() {} protected: constexpr explicit BlockId(uint32_t a) : Wrapped(a) {} }; +bool extract(XString str, GmLevel *lvl); class GmLevel { uint32_t bits; - friend bool extract(XString str, GmLevel *lvl) { return extract(str, &lvl->bits); } + friend bool extract(XString str, GmLevel *lvl); constexpr explicit GmLevel(uint32_t b) : bits(b) {} constexpr explicit diff --git a/src/mmo/login.t.hpp b/src/mmo/login.t.hpp new file mode 100644 index 0000000..f2c775a --- /dev/null +++ b/src/mmo/login.t.hpp @@ -0,0 +1,44 @@ +#pragma once +// login.t.hpp - externally useful types from login +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +namespace e +{ +enum class VERSION_2 : uint8_t +{ + /// client supports updatehost + UPDATEHOST = 0x01, + /// send servers in forward order + SERVERORDER = 0x02, +}; +ENUM_BITWISE_OPERATORS(VERSION_2) +} +using e::VERSION_2; +} // namespace tmwa diff --git a/src/mmo/md5more.cpp b/src/mmo/md5more.cpp deleted file mode 100644 index 4e5d2da..0000000 --- a/src/mmo/md5more.cpp +++ /dev/null @@ -1,159 +0,0 @@ -#include "md5more.hpp" -// md5more.cpp - Non-basic MD5 functions. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include - -#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 -// I once implemented an ostream that does it ... -MD5_state MD5_from_FILE(io::ReadFile& in) -{ - uint64_t total_len = 0; - - uint8_t buf[0x40]; - uint8_t block_len = 0; - - MD5_state state; - MD5_init(&state); - - MD5_block block; - - while (true) - { - size_t rv = in.get(sign_cast(buf + block_len), 0x40 - block_len); - if (!rv) - break; - total_len += 8 * rv; // in bits - block_len += rv; - if (block_len != 0x40) - continue; - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - block_len = 0; - } - // no more input, just pad and append the length - buf[block_len] = 0x80; - really_memset0(buf + block_len + 1, 0x40 - block_len - 1); - if (block_len < 0x38) - { - for (int i = 0; i < 8; i++) - buf[0x38 + i] = total_len >> i * 8; - } - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - if (0x38 <= block_len) - { - really_memset0(buf, 0x38); - for (int i = 0; i < 8; i++) - buf[0x38 + i] = total_len >> i * 8; - for (int i = 0; i < 0x10; i++) - X[i] = buf[4 * i + 0] | buf[4 * i + 1] << 8 | buf[4 * i + 2] << 16 | buf[4 * i + 3] << 24; - MD5_do_block(&state, block); - } - return state; -} - - -// Hash a password with a salt. -// Whoever wrote this FAILS programming -AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt) -{ - char cbuf[64] {}; - - // hash the key then the salt - // buf ends up as a 64-char NUL-terminated string - md5_string tbuf, tbuf2; - MD5_to_str(MD5_from_string(key), tbuf); - MD5_to_str(MD5_from_string(salt), tbuf2); - const auto it = std::copy(tbuf.begin(), tbuf.end(), std::begin(cbuf)); - auto it2 = std::copy(tbuf2.begin(), tbuf2.end(), it); - assert(it2 == std::end(cbuf)); - - md5_string tbuf3; - MD5_to_str(MD5_from_string(XString(std::begin(cbuf), it2, nullptr)), tbuf3); - - VString<31> obuf; - - // This truncates the string, but we have to keep it like that for compatibility - SNPRINTF(obuf, 32, "!%s$%s"_fmt, salt, tbuf3); - return stringish(obuf); -} - -SaltString make_salt(void) -{ - char salt[5]; - for (int i = 0; i < 5; i++) - // 126 would probably actually be okay - salt[i] = random_::in(48, 125); - return stringish(XString(salt + 0, salt + 5, nullptr)); -} - -bool pass_ok(AccountPass password, AccountCrypt crypted) -{ - // crypted is like !salt$hash - auto begin = crypted.begin() + 1; - auto end = std::find(begin, crypted.end(), '$'); - SaltString salt = stringish(crypted.xislice(begin, end)); - - return crypted == MD5_saltcrypt(password, salt); -} - -// [M|h]ashes up an IP address and a secret key -// to return a hopefully unique masked IP. -IP4Address MD5_ip(IP4Address ip) -{ - static SaltString secret = make_salt(); - - // MD5sum a secret + the IP address - VString<31> ipbuf; - SNPRINTF(ipbuf, 32, "%s %s"_fmt, ip, secret); - md5_binary obuf; - MD5_to_bin(MD5_from_string(ipbuf), obuf); - - // Fold the md5sum to 32 bits, pack the bytes to an in_addr - return IP4Address({ - static_cast(obuf[0] ^ obuf[1] ^ obuf[8] ^ obuf[9]), - static_cast(obuf[2] ^ obuf[3] ^ obuf[10] ^ obuf[11]), - static_cast(obuf[4] ^ obuf[5] ^ obuf[12] ^ obuf[13]), - static_cast(obuf[6] ^ obuf[7] ^ obuf[14] ^ obuf[15]), - }); -} -} // namespace tmwa diff --git a/src/mmo/md5more.hpp b/src/mmo/md5more.hpp deleted file mode 100644 index 7d50713..0000000 --- a/src/mmo/md5more.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#pragma once -// md5more.hpp - Non-basic MD5 functions. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include "../generic/md5.hpp" - -#include "../io/fwd.hpp" - -#include "../net/fwd.hpp" - - -namespace tmwa -{ -MD5_state MD5_from_FILE(io::ReadFile& in); - -// whoever wrote this fails basic understanding of -AccountCrypt MD5_saltcrypt(AccountPass key, SaltString salt); - -/// return some random characters -// Currently, returns a 5-char string -SaltString make_salt(void); - -/// check plaintext password against saved saltcrypt -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); -} // namespace tmwa diff --git a/src/mmo/mmo.hpp b/src/mmo/mmo.hpp deleted file mode 100644 index b5bcac8..0000000 --- a/src/mmo/mmo.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -// mmo.hpp - Huge mess of structures. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include "../compat/borrow.hpp" -#include "../compat/memory.hpp" - -#include "../proto2/net-CharData.hpp" -#include "../proto2/net-CharKey.hpp" -#include "../proto2/net-PartyMost.hpp" -#include "../proto2/net-SkillValue.hpp" - - -namespace tmwa -{ -inline -bool operator == (const SkillValue& l, const SkillValue& r) -{ - return l.lv == r.lv && l.flags == r.flags; -} -inline -bool operator != (const SkillValue& l, const SkillValue& r) -{ - return !(l == r); -} - -struct CharPair -{ - CharKey key; - std::unique_ptr data; - - CharPair() - : key{}, data(make_unique()) - {} -}; - -struct GM_Account -{ - AccountId account_id; - GmLevel level; -}; - -struct PartyPair -{ - PartyId party_id; - Borrowed party_most; - - PartyMost& operator *() const { return *party_most; } - Borrowed operator->() const { return party_most; } -}; -} // namespace tmwa diff --git a/src/mmo/skill.t.hpp b/src/mmo/skill.t.hpp new file mode 100644 index 0000000..d0e3926 --- /dev/null +++ b/src/mmo/skill.t.hpp @@ -0,0 +1,136 @@ +#pragma once +// skill.t.hpp - Old-style skills. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include + +#include "../generic/enum.hpp" + + +namespace tmwa +{ +// TODO remove most of these as their corresponding SkillIDs get deleted. +enum class StatusChange : uint16_t +{ + // indices into (map_session_data).status_change + SC_SENDMAX = 256, + + // sometimes means "none", sometimes not + NEGATIVE1 = 0xffff, + + // these ones are used by clif_status_change, + // e.g. by the magic system + ZERO = 0, + ATTACK_ICON_GENERIC = 2000, + ATTACK_ICON_SHEARING = 2001, + CART = 0x0c, + CLIF_OPTION_SC_INVISIBILITY = 0x1000, + CLIF_OPTION_SC_SCRIBE = 0x1001, + + // the rest are the normal effects + SC_SLOWPOISON = 14, // item script + + SC_WEIGHT50 = 35, // ? sort of used + SC_WEIGHT90 = 36, // definitely used + SC_SPEEDPOTION0 = 37, // item script + + SC_HEALING = 70, // item script + + SC_POISON = 132, // bad; actually used + + SC_ATKPOT = 185, // item script + SC_MATKPOT = 186, // unused, but kept for parallel + +// Added for Fate's spells + SC_HIDE = 194, // Hide from `detect' magic (PCs only) + SC_SHEARED = 194, // Has been sheared (mobs only) + SC_HALT_REGENERATE = 195, // Suspend regeneration + SC_FLYING_BACKPACK = 196, // Flying backpack + SC_MBARRIER = 197, // Magical barrier, magic resistance (val1 : power (%)) + SC_HASTE = 198, // `Haste' spell (val1 : power) + SC_PHYS_SHIELD = 199, // `Protect' spell, reduce damage (val1: power) + MAX_STATUSCHANGE = 200, +}; + +enum class SkillID : uint16_t +{ + // TODO: Remove these! + NEGATIVE = 0xffff, + ZERO = 0x0000, + ONE = 0x0001, + + // Basic skills. + // These should probably be made unconditional. + NV_EMOTE = 1, // + NV_TRADE = 2, // + NV_PARTY = 3, // + + AC_OWL = 45, // Mallard's Eye + + NPC_SELFDESTRUCTION = 175, // + + NPC_POISON = 178, // + + NPC_SUMMONSLAVE = 198, // + NPC_EMOTION = 199, // + + TMW_SKILLPOOL = 339, // skill pool size + + // magic skills + TMW_MAGIC = 340, // + TMW_MAGIC_LIFE = 341, // + TMW_MAGIC_WAR = 342, // + TMW_MAGIC_TRANSMUTE = 343, // + TMW_MAGIC_NATURE = 344, // + TMW_MAGIC_ETHER = 345, // + TMW_MAGIC_DARK = 346, // + TMW_MAGIC_LIGHT = 347, // + + // focusable skills + TMW_BRAWLING = 350, // + TMW_LUCKY_COUNTER = 351, // + TMW_SPEED = 352, // + TMW_RESIST_POISON = 353, // + TMW_ASTRAL_SOUL = 354, // + TMW_RAGING = 355, // + + // Note: this value is also hard-coded in common/mmo.hpp + MAX_SKILL_DB = 474, // not 450 +}; + +namespace e +{ +enum class SkillFlags : uint16_t +{ + ZERO = 0x00, + // is a pool skill + POOL_FLAG = 0x01, + // is an active pool skill + POOL_ACTIVE = 0x02, + // pool skill has been activated (used for clif) + POOL_ACTIVATED = 0x04, +}; +ENUM_BITWISE_OPERATORS(SkillFlags) +} +using e::SkillFlags; +} // namespace tmwa diff --git a/src/mmo/strs.hpp b/src/mmo/strs.hpp index fea0c98..6a132c2 100644 --- a/src/mmo/strs.hpp +++ b/src/mmo/strs.hpp @@ -123,4 +123,37 @@ CharName stringish(VString<23> iv) { return CharName(iv); } + +struct MobName : VString<23> {}; +struct NpcName : VString<23> {}; +struct ScriptLabel : VString<23> {}; +struct ItemName : VString<23> {}; + +// formerly VString<49>, as name::label +struct NpcEvent +{ + NpcName npc; + ScriptLabel label; + + explicit operator bool() + { + return npc || label; + } + bool operator !() + { + return !bool(*this); + } + + friend bool operator == (const NpcEvent& l, const NpcEvent& r) + { + return l.npc == r.npc && l.label == r.label; + } + + friend bool operator < (const NpcEvent& l, const NpcEvent& r) + { + return l.npc < r.npc || (l.npc == r.npc && l.label < r.label); + } + + friend VString<49> convert_for_printf(NpcEvent ev); +}; } // namespace tmwa diff --git a/src/mmo/utils.cpp b/src/mmo/utils.cpp deleted file mode 100644 index f8aff2e..0000000 --- a/src/mmo/utils.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "utils.hpp" -// utils.cpp - Useful stuff that hasn't been categorized. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include - -#include - -#include "../strings/zstring.hpp" -#include "../strings/xstring.hpp" - -#include "../io/cxxstdio.hpp" -#include "../io/write.hpp" - -#include "extract.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -//--------------------------------------------------- -// E-mail check: return 0 (not correct) or 1 (valid). -//--------------------------------------------------- -bool e_mail_check(XString email) -{ - // athena limits - if (email.size() < 3 || email.size() > 39) - return 0; - - // part of RFC limits (official reference of e-mail description) - XString::iterator at = std::find(email.begin(), email.end(), '@'); - if (at == email.end()) - return 0; - XString username = email.xislice_h(at); - XString hostname = email.xislice_t(at + 1); - if (!username || !hostname) - return 0; - if (hostname.contains('@')) - return 0; - if (hostname.front() == '.' || hostname.back() == '.') - return 0; - if (hostname.contains_seq(".."_s)) - return 0; - if (email.contains_any(" ;"_s)) - return 0; - return email.is_print(); -} - -//------------------------------------------------- -// Return numerical value of a switch configuration -// on/off, english, français, deutsch, español -//------------------------------------------------- -int config_switch(ZString str) -{ - if (str == "true"_s || str == "on"_s || str == "yes"_s - || str == "oui"_s || str == "ja"_s - || str == "si"_s) - return 1; - 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"_fmt, str); - abort(); -} - -static_assert(sizeof(timestamp_seconds_buffer) == 20, "seconds buffer"); -static_assert(sizeof(timestamp_milliseconds_buffer) == 24, "millis buffer"); - -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(VString<19>(strings::really_construct_from_a_pointer, buf)); -} -void stamp_time(timestamp_milliseconds_buffer& out) -{ - struct timeval tv; - 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(tv.tv_usec / 1000)); - out = stringish(VString<23>(strings::really_construct_from_a_pointer, buf)); -} - -void log_with_timestamp(io::WriteFile& out, XString line) -{ - if (!line) - { - out.put('\n'); - return; - } - timestamp_milliseconds_buffer tmpstr; - stamp_time(tmpstr); - out.really_put(tmpstr.data(), tmpstr.size()); - out.really_put(": ", 2); - out.put_line(line); -} -} // namespace tmwa diff --git a/src/mmo/utils.hpp b/src/mmo/utils.hpp deleted file mode 100644 index fc3ea74..0000000 --- a/src/mmo/utils.hpp +++ /dev/null @@ -1,167 +0,0 @@ -#pragma once -// utils.hpp - Useful stuff that hasn't been categorized. -// -// Copyright © ????-2004 Athena Dev Teams -// Copyright © 2004-2011 The Mana World Development Team -// Copyright © 2011-2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include -#include - -#include - -#include "../ints/little.hpp" - -#include "../strings/fwd.hpp" -#include "../strings/vstring.hpp" - -#include "../generic/operators.hpp" - -#include "../io/fwd.hpp" - - -namespace tmwa -{ -template -struct is_trivially_copyable -: std::integral_constant -{}; - -bool e_mail_check(XString email); -int config_switch (ZString str); - -template -void really_memzero_this(T *v) -{ - static_assert(is_trivially_copyable::value, "only for mostly-pod types"); - static_assert(std::is_class::value || std::is_union::value, "Only for user-defined structures (for now)"); - memset(v, '\0', sizeof(*v)); -} -template -void really_memzero_this(T (&)[n]) = delete; - -// Exists in place of time_t, to give it a predictable printf-format. -// (on x86 and amd64, time_t == long, but not on x32) -static_assert(sizeof(long long) >= sizeof(time_t), "long long >= time_t"); -struct TimeT : Comparable -{ - long long value; - - // conversion - TimeT(time_t t=0) : value(t) {} - TimeT(struct tm t) : value(timegm(&t)) {} - operator time_t() const { return value; } - operator struct tm() const { time_t v = value; return *gmtime(&v); } - - explicit operator bool() const { return value; } - bool operator !() const { return !value; } - - // prevent surprises - template - TimeT(T) = delete; - template - operator T() const = delete; - - static - TimeT now() - { - // poisoned, but this is still in header-land - return time(nullptr); - } - - bool error() const - { - return value == -1; - } - bool okay() const - { - return !error(); - } -}; - -inline -long long convert_for_printf(TimeT t) -{ - return t.value; -} - -// 2038 problem -inline __attribute__((warn_unused_result)) -bool native_to_network(Little32 *net, TimeT nat) -{ - time_t tmp = nat; - return native_to_network(net, static_cast(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(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(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(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); -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" -static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), - "timestamp size"); -#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) \ - stamp_time( \ - reinterpret_cast( \ - str + sizeof(str) \ - )[-1], \ - &t \ - ) -} // namespace tmwa diff --git a/src/mmo/version.cpp b/src/mmo/version.cpp index 7c63614..56e21dc 100644 --- a/src/mmo/version.cpp +++ b/src/mmo/version.cpp @@ -24,7 +24,7 @@ #include "../strings/xstring.hpp" -#include "extract.hpp" +#include "../io/extract.hpp" #include "../poison.hpp" diff --git a/src/mmo/version.hpp b/src/mmo/version.hpp index 6afcd58..1eed223 100644 --- a/src/mmo/version.hpp +++ b/src/mmo/version.hpp @@ -24,8 +24,6 @@ #include -#include "../strings/fwd.hpp" - namespace tmwa { diff --git a/src/monitor/main.cpp b/src/monitor/main.cpp index ec1139a..c27cf77 100644 --- a/src/monitor/main.cpp +++ b/src/monitor/main.cpp @@ -37,7 +37,8 @@ #include "../io/read.hpp" #include "../mmo/config_parse.hpp" -#include "../mmo/utils.hpp" + +#include "../net/timestamp-utils.hpp" #include "../poison.hpp" diff --git a/src/net/fwd.hpp b/src/net/fwd.hpp index 2097772..5de8450 100644 --- a/src/net/fwd.hpp +++ b/src/net/fwd.hpp @@ -20,6 +20,13 @@ #include "../sanity.hpp" +#include "../ints/fwd.hpp" // rank 1 +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../generic/fwd.hpp" // rank 3 +#include "../io/fwd.hpp" // rank 4 +// net/fwd.hpp is rank 5 + namespace tmwa { @@ -28,6 +35,4 @@ class Session; class IP4Address; class TimerData; - -enum class RecvResult; } // namespace tmwa diff --git a/src/net/ip.cpp b/src/net/ip.cpp index bfc2028..4ec022b 100644 --- a/src/net/ip.cpp +++ b/src/net/ip.cpp @@ -22,8 +22,7 @@ #include "../strings/vstring.hpp" #include "../io/cxxstdio.hpp" - -#include "../mmo/extract.hpp" +#include "../io/extract.hpp" #include "../poison.hpp" diff --git a/src/net/ip.hpp b/src/net/ip.hpp index e9e71f4..ab45c56 100644 --- a/src/net/ip.hpp +++ b/src/net/ip.hpp @@ -25,8 +25,6 @@ #include #include -#include "../strings/fwd.hpp" - namespace tmwa { diff --git a/src/net/packets.cpp b/src/net/packets.cpp deleted file mode 100644 index 3cba856..0000000 --- a/src/net/packets.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "packets.hpp" -// packets.cpp - palatable socket buffer accessors -// -// Copyright © 2014 Ben Longbons -// -// 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 . - -#include "../io/cxxstdio.hpp" -#include "../io/write.hpp" - -#include "../poison.hpp" - - -namespace tmwa -{ -size_t packet_avail(Session *s) -{ - return s->rdata_size - s->rdata_pos; -} - -bool packet_fetch(Session *s, size_t offset, Byte *data, size_t sz) -{ - if (packet_avail(s) < offset + sz) - return false; - const Byte *start = reinterpret_cast(&s->rdata[s->rdata_pos + offset]); - const Byte *end = start + sz; - std::copy(start, end, data); - return true; -} -void packet_discard(Session *s, size_t sz) -{ - s->rdata_pos += sz; - - assert (s->rdata_size >= s->rdata_pos); -} -bool packet_send(Session *s, const Byte *data, size_t sz) -{ - if (s->wdata_size + sz > s->max_wdata) - { - realloc_fifo(s, s->max_rdata, s->max_wdata << 1); - PRINTF("socket: %d wdata expanded to %zu bytes.\n"_fmt, s, s->max_wdata); - } - if (!s->max_wdata || !s->wdata) - { - return false; - } - s->wdata_size += sz; - - Byte *end = reinterpret_cast(&s->wdata[s->wdata_size + 0]); - Byte *start = end - sz; - std::copy(data, data + sz, start); - return true; -} - -void packet_dump(io::WriteFile& logfp, Session *s) -{ - FPRINTF(logfp, - "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"_fmt); - char tmpstr[16 + 1] {}; - int i; - for (i = 0; i < packet_avail(s); i++) - { - if ((i & 15) == 0) - FPRINTF(logfp, "%04X "_fmt, i); - Byte rfifob_ib; - packet_fetch(s, i, &rfifob_ib, 1); - uint8_t rfifob_i = rfifob_ib.value; - FPRINTF(logfp, "%02x "_fmt, rfifob_i); - if (rfifob_i > 0x1f) - tmpstr[i % 16] = rfifob_i; - else - tmpstr[i % 16] = '.'; - if ((i - 7) % 16 == 0) // -8 + 1 - FPRINTF(logfp, " "_fmt); - else if ((i + 1) % 16 == 0) - { - FPRINTF(logfp, " %s\n"_fmt, tmpstr); - std::fill(tmpstr + 0, tmpstr + 17, '\0'); - } - } - if (i % 16 != 0) - { - for (int j = i; j % 16 != 0; j++) - { - FPRINTF(logfp, " "_fmt); - if ((j - 7) % 16 == 0) // -8 + 1 - FPRINTF(logfp, " "_fmt); - } - FPRINTF(logfp, " %s\n"_fmt, tmpstr); - } - FPRINTF(logfp, "\n"_fmt); -} -} // namespace tmwa diff --git a/src/net/packets.hpp b/src/net/packets.hpp deleted file mode 100644 index 5cc377c..0000000 --- a/src/net/packets.hpp +++ /dev/null @@ -1,585 +0,0 @@ -#pragma once -// packets.hpp - palatable socket buffer accessors -// -// Copyright © 2014 Ben Longbons -// -// 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 . - -#include "fwd.hpp" - -#include - -#include "../compat/cast.hpp" - -#include "../ints/little.hpp" - -#include "../io/fwd.hpp" - -// TODO ordering violation, should invert -#include "../proto2/fwd.hpp" - -#include "socket.hpp" - - -namespace tmwa -{ -struct Buffer -{ - std::vector bytes; -}; - -enum class RecvResult -{ - Incomplete, - Complete, - Error, -}; - -enum class SendResult -{ - Success, - Fail, -}; - - -size_t packet_avail(Session *s); -void packet_dump(io::WriteFile& out, Session *s); - -bool packet_fetch(Session *s, size_t offset, Byte *data, size_t sz); -void packet_discard(Session *s, size_t sz); -bool packet_send(Session *s, const Byte *data, size_t sz); - -inline -bool packet_peek_id(Session *s, uint16_t *packet_id) -{ - Little16 id; - bool okay = packet_fetch(s, 0, reinterpret_cast(&id), 2); - if (okay) - { - if (!network_to_native(packet_id, id)) - { - s->set_eof(); - return false; - } - } - return okay; -} - -inline -void send_buffer(Session *s, const Buffer& buffer) -{ - bool ok = !buffer.bytes.empty() && packet_send(s, buffer.bytes.data(), buffer.bytes.size()); - if (!ok) - s->set_eof(); -} - -template -__attribute__((warn_unused_result)) -RecvResult net_recv_fpacket(Session *s, NetPacket_Fixed& fixed) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast(&fixed), sizeof(NetPacket_Fixed)); - if (ok) - { - packet_discard(s, sizeof(NetPacket_Fixed)); - return RecvResult::Complete; - } - return RecvResult::Incomplete; -} - -template -__attribute__((warn_unused_result)) -RecvResult net_recv_ppacket(Session *s, NetPacket_Payload& payload) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast(&payload), sizeof(NetPacket_Payload)); - if (ok) - { - packet_discard(s, sizeof(NetPacket_Payload)); - return RecvResult::Complete; - } - return RecvResult::Incomplete; -} - -template -__attribute__((warn_unused_result)) -RecvResult net_recv_vpacket(Session *s, NetPacket_Head& head, std::vector>& repeat) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast(&head), sizeof(NetPacket_Head)); - if (ok) - { - Packet_Head nat; - if (!network_to_native(&nat, head)) - return RecvResult::Error; - if (packet_avail(s) < nat.magic_packet_length) - return RecvResult::Incomplete; - if (nat.magic_packet_length < sizeof(NetPacket_Head)) - return RecvResult::Error; - size_t bytes_repeat = nat.magic_packet_length - sizeof(NetPacket_Head); - if (bytes_repeat % sizeof(NetPacket_Repeat)) - return RecvResult::Error; - repeat.resize(bytes_repeat / sizeof(NetPacket_Repeat)); - if (packet_fetch(s, sizeof(NetPacket_Head), reinterpret_cast(repeat.data()), bytes_repeat)) - { - packet_discard(s, nat.magic_packet_length); - return RecvResult::Complete; - } - return RecvResult::Incomplete; - } - return RecvResult::Incomplete; -} - -template -__attribute__((warn_unused_result)) -RecvResult net_recv_opacket(Session *s, NetPacket_Head& head, bool *has_opt, NetPacket_Option& opt) -{ - bool ok = packet_fetch(s, 0, reinterpret_cast(&head), sizeof(NetPacket_Head)); - if (ok) - { - Packet_Head nat; - if (!network_to_native(&nat, head)) - return RecvResult::Error; - if (packet_avail(s) < nat.magic_packet_length) - return RecvResult::Incomplete; - if (nat.magic_packet_length < sizeof(NetPacket_Head)) - return RecvResult::Error; - size_t bytes_repeat = nat.magic_packet_length - sizeof(NetPacket_Head); - if (bytes_repeat % sizeof(NetPacket_Option)) - return RecvResult::Error; - size_t has_opt_pls = bytes_repeat / sizeof(NetPacket_Option); - if (has_opt_pls > 1) - return RecvResult::Error; - *has_opt = has_opt_pls; - if (!*has_opt || packet_fetch(s, sizeof(NetPacket_Head), reinterpret_cast(&opt), sizeof(NetPacket_Option))) - { - packet_discard(s, nat.magic_packet_length); - return RecvResult::Complete; - } - return RecvResult::Incomplete; - } - return RecvResult::Incomplete; -} - - -template -Buffer create_fpacket(const Packet_Fixed& fixed) -{ - static_assert(id == Packet_Fixed::PACKET_ID, "Packet_Fixed::PACKET_ID"); - static_assert(size == sizeof(NetPacket_Fixed), "sizeof(NetPacket_Fixed)"); - - Buffer buf; - buf.bytes.resize(sizeof(NetPacket_Fixed)); - auto& net_fixed = reinterpret_cast&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_fixed, fixed)) - { - return Buffer(); - } - return buf; -} - -template -Buffer create_ppacket(Packet_Payload& payload) -{ - static_assert(id == Packet_Payload::PACKET_ID, "Packet_Payload::PACKET_ID"); - - if (id != 0x8000) - payload.magic_packet_length = sizeof(NetPacket_Payload); - - Buffer buf; - buf.bytes.resize(sizeof(NetPacket_Payload)); - auto& net_payload = reinterpret_cast&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_payload, payload)) - { - return Buffer(); - } - return buf; -} - -template -Buffer create_vpacket(Packet_Head& head, const std::vector>& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "sizeof(NetPacket_Head)"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - - // since these are already allocated, can't overflow address space - size_t total_size = sizeof(NetPacket_Head) + repeat.size() * sizeof(NetPacket_Repeat); - // truncates - head.magic_packet_length = total_size; - if (head.magic_packet_length != total_size) - { - return Buffer(); - } - - Buffer buf; - buf.bytes.resize(total_size); - auto& net_head = reinterpret_cast&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_head, head)) - { - return Buffer(); - } - for (size_t i = 0; i < repeat.size(); ++i) - { - auto& net_repeat_i = reinterpret_cast&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head) - + i * sizeof(NetPacket_Repeat))); - if (!native_to_network(&net_repeat_i, repeat[i])) - { - return Buffer(); - } - } - return buf; -} - -template -Buffer create_opacket(Packet_Head& head, bool has_opt, const Packet_Option& opt) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "sizeof(NetPacket_Head)"); - static_assert(id == Packet_Option::PACKET_ID, "Packet_Option::PACKET_ID"); - static_assert(optsize == sizeof(NetPacket_Option), "sizeof(NetPacket_Option)"); - - // since these are already allocated, can't overflow address space - size_t total_size = sizeof(NetPacket_Head) + has_opt * sizeof(NetPacket_Option); - // truncates - head.magic_packet_length = total_size; - if (head.magic_packet_length != total_size) - { - return Buffer(); - } - - Buffer buf; - buf.bytes.resize(total_size); - - auto& net_head = reinterpret_cast&>( - *(buf.bytes.begin() + 0)); - if (!native_to_network(&net_head, head)) - { - return Buffer(); - } - if (has_opt) - { - auto& net_opt = reinterpret_cast&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head))); - if (!native_to_network(&net_opt, opt)) - { - return Buffer(); - } - } - - return buf; -} - -template -void send_fpacket(Session *s, const Packet_Fixed& fixed) -{ - Buffer pkt = create_fpacket(fixed); - send_buffer(s, pkt); -} - -template -void send_ppacket(Session *s, Packet_Payload& payload) -{ - Buffer pkt = create_ppacket(payload); - send_buffer(s, pkt); -} - -template -void send_vpacket(Session *s, Packet_Head& head, const std::vector>& repeat) -{ - Buffer pkt = create_vpacket(head, repeat); - send_buffer(s, pkt); -} - -template -void send_opacket(Session *s, Packet_Head& head, bool has_opt, const Packet_Option& opt) -{ - Buffer pkt = create_opacket(head, has_opt, opt); - send_buffer(s, pkt); -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_fpacket(Session *s, Packet_Fixed& fixed) -{ - static_assert(id == Packet_Fixed::PACKET_ID, "Packet_Fixed::PACKET_ID"); - static_assert(size == sizeof(NetPacket_Fixed), "NetPacket_Fixed"); - - NetPacket_Fixed net_fixed; - RecvResult rv = net_recv_fpacket(s, net_fixed); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&fixed, net_fixed)) - return RecvResult::Error; - assert (fixed.magic_packet_id == Packet_Fixed::PACKET_ID); - } - return rv; -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_ppacket(Session *s, Packet_Payload& payload) -{ - static_assert(id == Packet_Payload::PACKET_ID, "Packet_Payload::PACKET_ID"); - - NetPacket_Payload net_payload; - RecvResult rv = net_recv_ppacket(s, net_payload); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&payload, net_payload)) - return RecvResult::Error; - assert (payload.magic_packet_id == Packet_Payload::PACKET_ID); - if (id == 0x8000) - { - // 0x8000 is special - if (packet_avail(s) < payload.magic_packet_length) - return RecvResult::Incomplete; - payload.magic_packet_length = 4; - return RecvResult::Complete; - } - if (payload.magic_packet_length != sizeof(net_payload)) - return RecvResult::Error; - } - return rv; -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_vpacket(Session *s, Packet_Head& head, std::vector>& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "NetPacket_Repeat"); - - NetPacket_Head net_head; - std::vector> net_repeat; - RecvResult rv = net_recv_vpacket(s, net_head, net_repeat); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&head, net_head)) - return RecvResult::Error; - assert (head.magic_packet_id == Packet_Head::PACKET_ID); - - repeat.resize(net_repeat.size()); - for (size_t i = 0; i < net_repeat.size(); ++i) - { - if (!network_to_native(&repeat[i], net_repeat[i])) - return RecvResult::Error; - } - } - return rv; -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_opacket(Session *s, Packet_Head& head, bool *has_opt, Packet_Option& opt) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); - static_assert(id == Packet_Option::PACKET_ID, "Packet_Option::PACKET_ID"); - static_assert(optsize == sizeof(NetPacket_Option), "NetPacket_Option"); - - NetPacket_Head net_head; - NetPacket_Option net_opt; - RecvResult rv = net_recv_opacket(s, net_head, has_opt, net_opt); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&head, net_head)) - return RecvResult::Error; - assert (head.magic_packet_id == Packet_Head::PACKET_ID); - - if (*has_opt) - { - if (!network_to_native(&opt, net_opt)) - return RecvResult::Error; - } - } - return rv; -} - - -// convenience for trailing strings - -template -Buffer create_vpacket(Packet_Head& head, const XString& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "NetPacket_Repeat"); - static_assert(repeatsize == 1, "repeatsize"); - - // since it's already allocated, it can't overflow address space - size_t total_length = sizeof(NetPacket_Head) + (repeat.size() + 1) * sizeof(NetPacket_Repeat); - head.magic_packet_length = total_length; - if (head.magic_packet_length != total_length) - { - return Buffer(); - } - - Buffer buf; - buf.bytes.resize(total_length); - auto& net_head = reinterpret_cast&>( - *(buf.bytes.begin() + 0)); - std::vector> net_repeat(repeat.size() + 1); - if (!native_to_network(&net_head, head)) - { - return Buffer(); - } - for (size_t i = 0; i < repeat.size(); ++i) - { - auto& net_repeat_i = reinterpret_cast&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head) - + i)); - net_repeat_i.c = Byte{static_cast(repeat[i])}; - } - auto& net_repeat_repeat_size = reinterpret_cast&>( - *(buf.bytes.begin() - + sizeof(NetPacket_Head) - + repeat.size())); - net_repeat_repeat_size.c = Byte{static_cast('\0')}; - return buf; -} - -template -void send_vpacket(Session *s, Packet_Head& head, const XString& repeat) -{ - Buffer pkt = create_vpacket(head, repeat); - send_buffer(s, pkt); -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_vpacket(Session *s, Packet_Head& head, AString& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "NetPacket_Repeat"); - static_assert(repeatsize == 1, "repeatsize"); - - NetPacket_Head net_head; - std::vector> net_repeat; - RecvResult rv = net_recv_vpacket(s, net_head, net_repeat); - assert (head.magic_packet_id == Packet_Head::PACKET_ID); - if (rv == RecvResult::Complete) - { - if (!network_to_native(&head, net_head)) - return RecvResult::Error; - // reinterpret_cast is needed to correctly handle an empty vector - const char *begin = sign_cast(net_repeat.data()); - const char *end = begin + net_repeat.size(); - end = std::find(begin, end, '\0'); - repeat = XString(begin, end, nullptr); - } - return rv; -} - - -// if there is nothing in the head but the id and length, use the below - -template -Buffer create_packet_repeatonly(const std::vector>& v) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - - Packet_Head head; - return create_vpacket(head, v); -} - -template -void send_packet_repeatonly(Session *s, const std::vector>& v) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - - Packet_Head head; - send_vpacket(s, head, v); -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_packet_repeatonly(Session *s, std::vector>& v) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - - Packet_Head head; - return recv_vpacket(s, head, v); -} - - -// and the combination of both of the above - -template -Buffer create_packet_repeatonly(const XString& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - static_assert(repeatsize == 1, "repeatsize"); - - Packet_Head head; - return create_vpacket(head, repeat); -} - -template -void send_packet_repeatonly(Session *s, const XString& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - static_assert(repeatsize == 1, "repeatsize"); - - Packet_Head head; - send_vpacket(s, head, repeat); -} - -template -__attribute__((warn_unused_result)) -RecvResult recv_packet_repeatonly(Session *s, AString& repeat) -{ - static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); - static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); - static_assert(headsize == 4, "repeat headsize"); - static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); - static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); - static_assert(repeatsize == 1, "repeatsize"); - - Packet_Head head; - return recv_vpacket(s, head, repeat); -} -} // namespace tmwa diff --git a/src/net/socket.cpp b/src/net/socket.cpp index a01cd81..fce45fb 100644 --- a/src/net/socket.cpp +++ b/src/net/socket.cpp @@ -34,10 +34,6 @@ #include "../io/cxxstdio.hpp" -// TODO get rid of ordering violations -#include "../mmo/utils.hpp" -#include "../mmo/core.hpp" - #include "timer.hpp" #include "../poison.hpp" @@ -399,7 +395,7 @@ void realloc_fifo(Session *s, size_t rfifo_size, size_t wfifo_size) } } -void do_sendrecv(interval_t next_ms) +bool do_sendrecv(interval_t next_ms) { bool any = false; io::FD_Set rfd = readfds, wfd; @@ -419,9 +415,9 @@ void do_sendrecv(interval_t next_ms) { PRINTF("Shutting down - nothing to do\n"_fmt); // TODO hoist this - runflag = false; + return false; } - return; + return true; } struct timeval timeout; { @@ -431,7 +427,7 @@ void do_sendrecv(interval_t next_ms) timeout.tv_usec = next_us.count(); } if (io::FD_Set::select(fd_max, &rfd, &wfd, nullptr, &timeout) <= 0) - return; + return true; for (io::FD i : iter_fds()) { Session *s = get_session(i); @@ -451,9 +447,10 @@ void do_sendrecv(interval_t next_ms) s->func_recv(s); } } + return true; } -void do_parsepacket(void) +bool do_parsepacket(void) { for (io::FD i : iter_fds()) { @@ -483,5 +480,6 @@ void do_parsepacket(void) /// Reclaim buffer space for what was read RFIFOFLUSH(s); } + return true; } } // namespace tmwa diff --git a/src/net/socket.hpp b/src/net/socket.hpp index 576ef85..d6caefd 100644 --- a/src/net/socket.hpp +++ b/src/net/socket.hpp @@ -22,20 +22,19 @@ #include "fwd.hpp" -#include - #include +#include #include -#include "../compat/iter.hpp" -#include "../compat/rawmem.hpp" -#include "../compat/time_t.hpp" - #include "../strings/astring.hpp" #include "../strings/vstring.hpp" #include "../strings/xstring.hpp" +#include "../compat/iter.hpp" +#include "../compat/rawmem.hpp" +#include "../compat/time_t.hpp" + #include "../generic/dumb_ptr.hpp" #include "../io/fd.hpp" @@ -125,8 +124,8 @@ public: io::FD fd; - friend void do_sendrecv(interval_t next); - friend void do_parsepacket(void); + friend bool do_sendrecv(interval_t next); + friend bool do_parsepacket(void); friend void delete_session(Session *); }; @@ -171,7 +170,7 @@ 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); +bool do_sendrecv(interval_t next); /// Call the parser function for every socket that has read data -void do_parsepacket(void); +bool do_parsepacket(void); } // namespace tmwa diff --git a/src/net/timer.hpp b/src/net/timer.hpp index 338e339..5e7cc90 100644 --- a/src/net/timer.hpp +++ b/src/net/timer.hpp @@ -21,11 +21,8 @@ // along with this program. If not, see . #include "timer.t.hpp" - #include "fwd.hpp" -#include "../strings/fwd.hpp" - namespace tmwa { diff --git a/src/net/timestamp-utils.cpp b/src/net/timestamp-utils.cpp new file mode 100644 index 0000000..b5873ca --- /dev/null +++ b/src/net/timestamp-utils.cpp @@ -0,0 +1,72 @@ +#include "timestamp-utils.hpp" +// timestamp-utils.cpp - Useful stuff that hasn't been categorized. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include + +#include + +#include "../strings/xstring.hpp" + +#include "../compat/time_t.hpp" + +#include "../io/write.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +static_assert(sizeof(timestamp_seconds_buffer) == 20, "seconds buffer"); +static_assert(sizeof(timestamp_milliseconds_buffer) == 24, "millis buffer"); + +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(VString<19>(strings::really_construct_from_a_pointer, buf)); +} +void stamp_time(timestamp_milliseconds_buffer& out) +{ + struct timeval tv; + 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(tv.tv_usec / 1000)); + out = stringish(VString<23>(strings::really_construct_from_a_pointer, buf)); +} + +void log_with_timestamp(io::WriteFile& out, XString line) +{ + if (!line) + { + out.put('\n'); + return; + } + timestamp_milliseconds_buffer tmpstr; + stamp_time(tmpstr); + out.really_put(tmpstr.data(), tmpstr.size()); + out.really_put(": ", 2); + out.put_line(line); +} +} // namespace tmwa diff --git a/src/net/timestamp-utils.hpp b/src/net/timestamp-utils.hpp new file mode 100644 index 0000000..f5b5dce --- /dev/null +++ b/src/net/timestamp-utils.hpp @@ -0,0 +1,54 @@ +#pragma once +// timestamp-utils.hpp - Useful stuff that hasn't been categorized. +// +// Copyright © ????-2004 Athena Dev Teams +// Copyright © 2004-2011 The Mana World Development Team +// Copyright © 2011-2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include "../strings/vstring.hpp" + + +namespace tmwa +{ +struct timestamp_seconds_buffer : VString<19> {}; +struct timestamp_milliseconds_buffer : VString<23> {}; +void stamp_time(timestamp_seconds_buffer&, const TimeT *t=nullptr); +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" +static_assert(sizeof(TIMESTAMP_DUMMY) == sizeof(timestamp_seconds_buffer), + "timestamp size"); +#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) \ + stamp_time( \ + reinterpret_cast( \ + str + sizeof(str) \ + )[-1], \ + &t \ + ) +} // namespace tmwa diff --git a/src/proto-base/fwd.hpp b/src/proto-base/fwd.hpp index 560f7fc..1790717 100644 --- a/src/proto-base/fwd.hpp +++ b/src/proto-base/fwd.hpp @@ -20,6 +20,11 @@ #include "../sanity.hpp" +#include "../strings/fwd.hpp" // rank 1 +#include "../generic/fwd.hpp" // rank 3 +#include "../mmo/fwd.hpp" // rank 6 +// proto-base/fwd.hpp is rank 7 + namespace tmwa { diff --git a/src/range/fwd.hpp b/src/range/fwd.hpp index 646eadb..4bad327 100644 --- a/src/range/fwd.hpp +++ b/src/range/fwd.hpp @@ -20,6 +20,8 @@ #include "../sanity.hpp" +// range/fwd.hpp is rank 1 + namespace tmwa { diff --git a/src/sexpr/fwd.hpp b/src/sexpr/fwd.hpp index 580b322..41e21a1 100644 --- a/src/sexpr/fwd.hpp +++ b/src/sexpr/fwd.hpp @@ -20,6 +20,11 @@ #include "../sanity.hpp" +#include "../strings/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../io/fwd.hpp" // rank 4 +// sexpr/fwd.hpp is rank 5 + namespace tmwa { diff --git a/src/sexpr/lexer.hpp b/src/sexpr/lexer.hpp index 63be72d..744d8c5 100644 --- a/src/sexpr/lexer.hpp +++ b/src/sexpr/lexer.hpp @@ -22,7 +22,6 @@ #include -#include "../strings/fwd.hpp" #include "../strings/astring.hpp" #include "../strings/zstring.hpp" diff --git a/src/sexpr/parser.hpp b/src/sexpr/parser.hpp index feed636..cfe8212 100644 --- a/src/sexpr/parser.hpp +++ b/src/sexpr/parser.hpp @@ -22,8 +22,6 @@ #include -#include "../strings/fwd.hpp" - #include "../io/line.hpp" #include "lexer.hpp" diff --git a/src/strings/astring.py b/src/strings/astring.py index f4cbf66..a3306d9 100644 --- a/src/strings/astring.py +++ b/src/strings/astring.py @@ -25,7 +25,7 @@ class AString(object): test_extra = ''' using tmwa::operator "" _s; - #include "../src/strings/zstring.hpp" + #include "../strings/zstring.hpp" ''' tests = [ diff --git a/src/strings/fwd.hpp b/src/strings/fwd.hpp index b1b8266..29762f9 100644 --- a/src/strings/fwd.hpp +++ b/src/strings/fwd.hpp @@ -23,6 +23,8 @@ #include #include +// strings/fwd.hpp is rank 1 + namespace tmwa { diff --git a/src/strings/rstring.py b/src/strings/rstring.py index 61603d8..27e9ff2 100644 --- a/src/strings/rstring.py +++ b/src/strings/rstring.py @@ -31,7 +31,7 @@ class RString(object): test_extra = ''' using tmwa::operator "" _s; - #include "../src/strings/zstring.hpp" + #include "../strings/zstring.hpp" ''' tests = [ diff --git a/src/tests/fwd.hpp b/src/tests/fwd.hpp index 48627da..3ee52ff 100644 --- a/src/tests/fwd.hpp +++ b/src/tests/fwd.hpp @@ -20,6 +20,10 @@ #include "../sanity.hpp" +#include "../strings/fwd.hpp" // rank 1 +#include "../io/fwd.hpp" // rank 4 +// tests/fwd.hpp is rank 5, but gtests do not require rank + namespace tmwa { diff --git a/src/wire/fwd.hpp b/src/wire/fwd.hpp new file mode 100644 index 0000000..83d5b20 --- /dev/null +++ b/src/wire/fwd.hpp @@ -0,0 +1,34 @@ +#pragma once +// wire/fwd.hpp - list of type names for network packets +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "../sanity.hpp" + +#include "../ints/fwd.hpp" // rank 1 +#include "../compat/fwd.hpp" // rank 2 +#include "../io/fwd.hpp" // rank 4 +#include "../net/fwd.hpp" // rank 5 +#include "../proto2/fwd.hpp" // rank 8 +// wire/fwd.hpp is rank 9 + +namespace tmwa +{ +enum class RecvResult; +// meh, add more when I feel like it +} // namespace tmwa diff --git a/src/wire/packets.cpp b/src/wire/packets.cpp new file mode 100644 index 0000000..3cba856 --- /dev/null +++ b/src/wire/packets.cpp @@ -0,0 +1,106 @@ +#include "packets.hpp" +// packets.cpp - palatable socket buffer accessors +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "../io/cxxstdio.hpp" +#include "../io/write.hpp" + +#include "../poison.hpp" + + +namespace tmwa +{ +size_t packet_avail(Session *s) +{ + return s->rdata_size - s->rdata_pos; +} + +bool packet_fetch(Session *s, size_t offset, Byte *data, size_t sz) +{ + if (packet_avail(s) < offset + sz) + return false; + const Byte *start = reinterpret_cast(&s->rdata[s->rdata_pos + offset]); + const Byte *end = start + sz; + std::copy(start, end, data); + return true; +} +void packet_discard(Session *s, size_t sz) +{ + s->rdata_pos += sz; + + assert (s->rdata_size >= s->rdata_pos); +} +bool packet_send(Session *s, const Byte *data, size_t sz) +{ + if (s->wdata_size + sz > s->max_wdata) + { + realloc_fifo(s, s->max_rdata, s->max_wdata << 1); + PRINTF("socket: %d wdata expanded to %zu bytes.\n"_fmt, s, s->max_wdata); + } + if (!s->max_wdata || !s->wdata) + { + return false; + } + s->wdata_size += sz; + + Byte *end = reinterpret_cast(&s->wdata[s->wdata_size + 0]); + Byte *start = end - sz; + std::copy(data, data + sz, start); + return true; +} + +void packet_dump(io::WriteFile& logfp, Session *s) +{ + FPRINTF(logfp, + "---- 00-01-02-03-04-05-06-07 08-09-0A-0B-0C-0D-0E-0F\n"_fmt); + char tmpstr[16 + 1] {}; + int i; + for (i = 0; i < packet_avail(s); i++) + { + if ((i & 15) == 0) + FPRINTF(logfp, "%04X "_fmt, i); + Byte rfifob_ib; + packet_fetch(s, i, &rfifob_ib, 1); + uint8_t rfifob_i = rfifob_ib.value; + FPRINTF(logfp, "%02x "_fmt, rfifob_i); + if (rfifob_i > 0x1f) + tmpstr[i % 16] = rfifob_i; + else + tmpstr[i % 16] = '.'; + if ((i - 7) % 16 == 0) // -8 + 1 + FPRINTF(logfp, " "_fmt); + else if ((i + 1) % 16 == 0) + { + FPRINTF(logfp, " %s\n"_fmt, tmpstr); + std::fill(tmpstr + 0, tmpstr + 17, '\0'); + } + } + if (i % 16 != 0) + { + for (int j = i; j % 16 != 0; j++) + { + FPRINTF(logfp, " "_fmt); + if ((j - 7) % 16 == 0) // -8 + 1 + FPRINTF(logfp, " "_fmt); + } + FPRINTF(logfp, " %s\n"_fmt, tmpstr); + } + FPRINTF(logfp, "\n"_fmt); +} +} // namespace tmwa diff --git a/src/wire/packets.hpp b/src/wire/packets.hpp new file mode 100644 index 0000000..a233344 --- /dev/null +++ b/src/wire/packets.hpp @@ -0,0 +1,582 @@ +#pragma once +// packets.hpp - palatable socket buffer accessors +// +// Copyright © 2014 Ben Longbons +// +// 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 . + +#include "fwd.hpp" + +#include + +#include "../ints/little.hpp" + +#include "../compat/cast.hpp" + +#include "../proto2/fwd.hpp" + +#include "../net/socket.hpp" + + +namespace tmwa +{ +struct Buffer +{ + std::vector bytes; +}; + +enum class RecvResult +{ + Incomplete, + Complete, + Error, +}; + +enum class SendResult +{ + Success, + Fail, +}; + + +size_t packet_avail(Session *s); +void packet_dump(io::WriteFile& out, Session *s); + +bool packet_fetch(Session *s, size_t offset, Byte *data, size_t sz); +void packet_discard(Session *s, size_t sz); +bool packet_send(Session *s, const Byte *data, size_t sz); + +inline +bool packet_peek_id(Session *s, uint16_t *packet_id) +{ + Little16 id; + bool okay = packet_fetch(s, 0, reinterpret_cast(&id), 2); + if (okay) + { + if (!network_to_native(packet_id, id)) + { + s->set_eof(); + return false; + } + } + return okay; +} + +inline +void send_buffer(Session *s, const Buffer& buffer) +{ + bool ok = !buffer.bytes.empty() && packet_send(s, buffer.bytes.data(), buffer.bytes.size()); + if (!ok) + s->set_eof(); +} + +template +__attribute__((warn_unused_result)) +RecvResult net_recv_fpacket(Session *s, NetPacket_Fixed& fixed) +{ + bool ok = packet_fetch(s, 0, reinterpret_cast(&fixed), sizeof(NetPacket_Fixed)); + if (ok) + { + packet_discard(s, sizeof(NetPacket_Fixed)); + return RecvResult::Complete; + } + return RecvResult::Incomplete; +} + +template +__attribute__((warn_unused_result)) +RecvResult net_recv_ppacket(Session *s, NetPacket_Payload& payload) +{ + bool ok = packet_fetch(s, 0, reinterpret_cast(&payload), sizeof(NetPacket_Payload)); + if (ok) + { + packet_discard(s, sizeof(NetPacket_Payload)); + return RecvResult::Complete; + } + return RecvResult::Incomplete; +} + +template +__attribute__((warn_unused_result)) +RecvResult net_recv_vpacket(Session *s, NetPacket_Head& head, std::vector>& repeat) +{ + bool ok = packet_fetch(s, 0, reinterpret_cast(&head), sizeof(NetPacket_Head)); + if (ok) + { + Packet_Head nat; + if (!network_to_native(&nat, head)) + return RecvResult::Error; + if (packet_avail(s) < nat.magic_packet_length) + return RecvResult::Incomplete; + if (nat.magic_packet_length < sizeof(NetPacket_Head)) + return RecvResult::Error; + size_t bytes_repeat = nat.magic_packet_length - sizeof(NetPacket_Head); + if (bytes_repeat % sizeof(NetPacket_Repeat)) + return RecvResult::Error; + repeat.resize(bytes_repeat / sizeof(NetPacket_Repeat)); + if (packet_fetch(s, sizeof(NetPacket_Head), reinterpret_cast(repeat.data()), bytes_repeat)) + { + packet_discard(s, nat.magic_packet_length); + return RecvResult::Complete; + } + return RecvResult::Incomplete; + } + return RecvResult::Incomplete; +} + +template +__attribute__((warn_unused_result)) +RecvResult net_recv_opacket(Session *s, NetPacket_Head& head, bool *has_opt, NetPacket_Option& opt) +{ + bool ok = packet_fetch(s, 0, reinterpret_cast(&head), sizeof(NetPacket_Head)); + if (ok) + { + Packet_Head nat; + if (!network_to_native(&nat, head)) + return RecvResult::Error; + if (packet_avail(s) < nat.magic_packet_length) + return RecvResult::Incomplete; + if (nat.magic_packet_length < sizeof(NetPacket_Head)) + return RecvResult::Error; + size_t bytes_repeat = nat.magic_packet_length - sizeof(NetPacket_Head); + if (bytes_repeat % sizeof(NetPacket_Option)) + return RecvResult::Error; + size_t has_opt_pls = bytes_repeat / sizeof(NetPacket_Option); + if (has_opt_pls > 1) + return RecvResult::Error; + *has_opt = has_opt_pls; + if (!*has_opt || packet_fetch(s, sizeof(NetPacket_Head), reinterpret_cast(&opt), sizeof(NetPacket_Option))) + { + packet_discard(s, nat.magic_packet_length); + return RecvResult::Complete; + } + return RecvResult::Incomplete; + } + return RecvResult::Incomplete; +} + + +template +Buffer create_fpacket(const Packet_Fixed& fixed) +{ + static_assert(id == Packet_Fixed::PACKET_ID, "Packet_Fixed::PACKET_ID"); + static_assert(size == sizeof(NetPacket_Fixed), "sizeof(NetPacket_Fixed)"); + + Buffer buf; + buf.bytes.resize(sizeof(NetPacket_Fixed)); + auto& net_fixed = reinterpret_cast&>( + *(buf.bytes.begin() + 0)); + if (!native_to_network(&net_fixed, fixed)) + { + return Buffer(); + } + return buf; +} + +template +Buffer create_ppacket(Packet_Payload& payload) +{ + static_assert(id == Packet_Payload::PACKET_ID, "Packet_Payload::PACKET_ID"); + + if (id != 0x8000) + payload.magic_packet_length = sizeof(NetPacket_Payload); + + Buffer buf; + buf.bytes.resize(sizeof(NetPacket_Payload)); + auto& net_payload = reinterpret_cast&>( + *(buf.bytes.begin() + 0)); + if (!native_to_network(&net_payload, payload)) + { + return Buffer(); + } + return buf; +} + +template +Buffer create_vpacket(Packet_Head& head, const std::vector>& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "sizeof(NetPacket_Head)"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + + // since these are already allocated, can't overflow address space + size_t total_size = sizeof(NetPacket_Head) + repeat.size() * sizeof(NetPacket_Repeat); + // truncates + head.magic_packet_length = total_size; + if (head.magic_packet_length != total_size) + { + return Buffer(); + } + + Buffer buf; + buf.bytes.resize(total_size); + auto& net_head = reinterpret_cast&>( + *(buf.bytes.begin() + 0)); + if (!native_to_network(&net_head, head)) + { + return Buffer(); + } + for (size_t i = 0; i < repeat.size(); ++i) + { + auto& net_repeat_i = reinterpret_cast&>( + *(buf.bytes.begin() + + sizeof(NetPacket_Head) + + i * sizeof(NetPacket_Repeat))); + if (!native_to_network(&net_repeat_i, repeat[i])) + { + return Buffer(); + } + } + return buf; +} + +template +Buffer create_opacket(Packet_Head& head, bool has_opt, const Packet_Option& opt) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "sizeof(NetPacket_Head)"); + static_assert(id == Packet_Option::PACKET_ID, "Packet_Option::PACKET_ID"); + static_assert(optsize == sizeof(NetPacket_Option), "sizeof(NetPacket_Option)"); + + // since these are already allocated, can't overflow address space + size_t total_size = sizeof(NetPacket_Head) + has_opt * sizeof(NetPacket_Option); + // truncates + head.magic_packet_length = total_size; + if (head.magic_packet_length != total_size) + { + return Buffer(); + } + + Buffer buf; + buf.bytes.resize(total_size); + + auto& net_head = reinterpret_cast&>( + *(buf.bytes.begin() + 0)); + if (!native_to_network(&net_head, head)) + { + return Buffer(); + } + if (has_opt) + { + auto& net_opt = reinterpret_cast&>( + *(buf.bytes.begin() + + sizeof(NetPacket_Head))); + if (!native_to_network(&net_opt, opt)) + { + return Buffer(); + } + } + + return buf; +} + +template +void send_fpacket(Session *s, const Packet_Fixed& fixed) +{ + Buffer pkt = create_fpacket(fixed); + send_buffer(s, pkt); +} + +template +void send_ppacket(Session *s, Packet_Payload& payload) +{ + Buffer pkt = create_ppacket(payload); + send_buffer(s, pkt); +} + +template +void send_vpacket(Session *s, Packet_Head& head, const std::vector>& repeat) +{ + Buffer pkt = create_vpacket(head, repeat); + send_buffer(s, pkt); +} + +template +void send_opacket(Session *s, Packet_Head& head, bool has_opt, const Packet_Option& opt) +{ + Buffer pkt = create_opacket(head, has_opt, opt); + send_buffer(s, pkt); +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_fpacket(Session *s, Packet_Fixed& fixed) +{ + static_assert(id == Packet_Fixed::PACKET_ID, "Packet_Fixed::PACKET_ID"); + static_assert(size == sizeof(NetPacket_Fixed), "NetPacket_Fixed"); + + NetPacket_Fixed net_fixed; + RecvResult rv = net_recv_fpacket(s, net_fixed); + if (rv == RecvResult::Complete) + { + if (!network_to_native(&fixed, net_fixed)) + return RecvResult::Error; + assert (fixed.magic_packet_id == Packet_Fixed::PACKET_ID); + } + return rv; +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_ppacket(Session *s, Packet_Payload& payload) +{ + static_assert(id == Packet_Payload::PACKET_ID, "Packet_Payload::PACKET_ID"); + + NetPacket_Payload net_payload; + RecvResult rv = net_recv_ppacket(s, net_payload); + if (rv == RecvResult::Complete) + { + if (!network_to_native(&payload, net_payload)) + return RecvResult::Error; + assert (payload.magic_packet_id == Packet_Payload::PACKET_ID); + if (id == 0x8000) + { + // 0x8000 is special + if (packet_avail(s) < payload.magic_packet_length) + return RecvResult::Incomplete; + payload.magic_packet_length = 4; + return RecvResult::Complete; + } + if (payload.magic_packet_length != sizeof(net_payload)) + return RecvResult::Error; + } + return rv; +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_vpacket(Session *s, Packet_Head& head, std::vector>& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "NetPacket_Repeat"); + + NetPacket_Head net_head; + std::vector> net_repeat; + RecvResult rv = net_recv_vpacket(s, net_head, net_repeat); + if (rv == RecvResult::Complete) + { + if (!network_to_native(&head, net_head)) + return RecvResult::Error; + assert (head.magic_packet_id == Packet_Head::PACKET_ID); + + repeat.resize(net_repeat.size()); + for (size_t i = 0; i < net_repeat.size(); ++i) + { + if (!network_to_native(&repeat[i], net_repeat[i])) + return RecvResult::Error; + } + } + return rv; +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_opacket(Session *s, Packet_Head& head, bool *has_opt, Packet_Option& opt) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); + static_assert(id == Packet_Option::PACKET_ID, "Packet_Option::PACKET_ID"); + static_assert(optsize == sizeof(NetPacket_Option), "NetPacket_Option"); + + NetPacket_Head net_head; + NetPacket_Option net_opt; + RecvResult rv = net_recv_opacket(s, net_head, has_opt, net_opt); + if (rv == RecvResult::Complete) + { + if (!network_to_native(&head, net_head)) + return RecvResult::Error; + assert (head.magic_packet_id == Packet_Head::PACKET_ID); + + if (*has_opt) + { + if (!network_to_native(&opt, net_opt)) + return RecvResult::Error; + } + } + return rv; +} + + +// convenience for trailing strings + +template +Buffer create_vpacket(Packet_Head& head, const XString& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "NetPacket_Repeat"); + static_assert(repeatsize == 1, "repeatsize"); + + // since it's already allocated, it can't overflow address space + size_t total_length = sizeof(NetPacket_Head) + (repeat.size() + 1) * sizeof(NetPacket_Repeat); + head.magic_packet_length = total_length; + if (head.magic_packet_length != total_length) + { + return Buffer(); + } + + Buffer buf; + buf.bytes.resize(total_length); + auto& net_head = reinterpret_cast&>( + *(buf.bytes.begin() + 0)); + std::vector> net_repeat(repeat.size() + 1); + if (!native_to_network(&net_head, head)) + { + return Buffer(); + } + for (size_t i = 0; i < repeat.size(); ++i) + { + auto& net_repeat_i = reinterpret_cast&>( + *(buf.bytes.begin() + + sizeof(NetPacket_Head) + + i)); + net_repeat_i.c = Byte{static_cast(repeat[i])}; + } + auto& net_repeat_repeat_size = reinterpret_cast&>( + *(buf.bytes.begin() + + sizeof(NetPacket_Head) + + repeat.size())); + net_repeat_repeat_size.c = Byte{static_cast('\0')}; + return buf; +} + +template +void send_vpacket(Session *s, Packet_Head& head, const XString& repeat) +{ + Buffer pkt = create_vpacket(head, repeat); + send_buffer(s, pkt); +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_vpacket(Session *s, Packet_Head& head, AString& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "NetPacket_Head"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "NetPacket_Repeat"); + static_assert(repeatsize == 1, "repeatsize"); + + NetPacket_Head net_head; + std::vector> net_repeat; + RecvResult rv = net_recv_vpacket(s, net_head, net_repeat); + assert (head.magic_packet_id == Packet_Head::PACKET_ID); + if (rv == RecvResult::Complete) + { + if (!network_to_native(&head, net_head)) + return RecvResult::Error; + // reinterpret_cast is needed to correctly handle an empty vector + const char *begin = sign_cast(net_repeat.data()); + const char *end = begin + net_repeat.size(); + end = std::find(begin, end, '\0'); + repeat = XString(begin, end, nullptr); + } + return rv; +} + + +// if there is nothing in the head but the id and length, use the below + +template +Buffer create_packet_repeatonly(const std::vector>& v) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); + static_assert(headsize == 4, "repeat headsize"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + + Packet_Head head; + return create_vpacket(head, v); +} + +template +void send_packet_repeatonly(Session *s, const std::vector>& v) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); + static_assert(headsize == 4, "repeat headsize"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + + Packet_Head head; + send_vpacket(s, head, v); +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_packet_repeatonly(Session *s, std::vector>& v) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); + static_assert(headsize == 4, "repeat headsize"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + + Packet_Head head; + return recv_vpacket(s, head, v); +} + + +// and the combination of both of the above + +template +Buffer create_packet_repeatonly(const XString& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); + static_assert(headsize == 4, "repeat headsize"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + static_assert(repeatsize == 1, "repeatsize"); + + Packet_Head head; + return create_vpacket(head, repeat); +} + +template +void send_packet_repeatonly(Session *s, const XString& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); + static_assert(headsize == 4, "repeat headsize"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + static_assert(repeatsize == 1, "repeatsize"); + + Packet_Head head; + send_vpacket(s, head, repeat); +} + +template +__attribute__((warn_unused_result)) +RecvResult recv_packet_repeatonly(Session *s, AString& repeat) +{ + static_assert(id == Packet_Head::PACKET_ID, "Packet_Head::PACKET_ID"); + static_assert(headsize == sizeof(NetPacket_Head), "repeat headsize"); + static_assert(headsize == 4, "repeat headsize"); + static_assert(id == Packet_Repeat::PACKET_ID, "Packet_Repeat::PACKET_ID"); + static_assert(repeatsize == sizeof(NetPacket_Repeat), "sizeof(NetPacket_Repeat)"); + static_assert(repeatsize == 1, "repeatsize"); + + Packet_Head head; + return recv_vpacket(s, head, repeat); +} +} // namespace tmwa -- cgit v1.2.3-70-g09d2