From 10a040e7cb43583f3cd1fe93306f0cbed15bc03f Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 01:42:58 +0300 Subject: [PATCH 1/8] refact(serializable): rename Id -> SerId --- OSS13 Client/Sources/Network/Connection.cpp | 2 +- .../Sources/Network/SyncCommandsProcessor.cpp | 2 +- .../Sources/Network/NetworkController.cpp | 2 +- .../Sources/Player/PlayerCommandsProcessor.cpp | 2 +- OSS13 Server/Sources/World/Tile.cpp | 2 +- .../Sources/Shared/Network/ISerializable.cpp | 2 +- .../Sources/Shared/Network/ISerializable.h | 18 ++++++++---------- 7 files changed, 14 insertions(+), 16 deletions(-) diff --git a/OSS13 Client/Sources/Network/Connection.cpp b/OSS13 Client/Sources/Network/Connection.cpp index 33cf61d..3640c88 100644 --- a/OSS13 Client/Sources/Network/Connection.cpp +++ b/OSS13 Client/Sources/Network/Connection.cpp @@ -122,7 +122,7 @@ bool Connection::parsePacket(sf::Packet &packet) { auto generalCommand = uptr(dynamic_cast(serializable.release())); if (!generalCommand) { - LOGE << "Unknown serializable (id is 0x" << std::hex << serializable->Id() << ") is received!"; + LOGE << "Unknown serializable (id is 0x" << std::hex << serializable->SerID() << ") is received!"; return false; } diff --git a/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp b/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp index 9ce8776..5647ba4 100644 --- a/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp +++ b/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp @@ -28,7 +28,7 @@ void SyncCommandsProcessor::ProcessCommand(network::protocol::Command &generalCo _REGISTRATE_COMMAND_PROCESSOR(UpdateWindowCommand); _REGISTRATE_COMMAND_PROCESSOR(AddChatMessageCommand); - LOGE << __FUNCTION__ << ": unknown command (ser id is 0x" << std::hex << generalCommand.Id() << ") was not processed!"; + LOGE << __FUNCTION__ << ": unknown command (ser id is 0x" << std::hex << generalCommand.SerID() << ") was not processed!"; } void SyncCommandsProcessor::commandProcessor_AuthorizationSuccessCommand(network::protocol::server::AuthorizationSuccessCommand &) { diff --git a/OSS13 Server/Sources/Network/NetworkController.cpp b/OSS13 Server/Sources/Network/NetworkController.cpp index 643a386..6820368 100644 --- a/OSS13 Server/Sources/Network/NetworkController.cpp +++ b/OSS13 Server/Sources/Network/NetworkController.cpp @@ -117,7 +117,7 @@ bool NetworkController::parsePacket(sf::Packet &packet, sptr &connec auto generalCommand = uptr(dynamic_cast(serializable.release())); if (!generalCommand) { - LOGE << "Unknown serializable (id is 0x" << std::hex << serializable->Id() << ") is received from " + LOGE << "Unknown serializable (id is 0x" << std::hex << serializable->SerID() << ") is received from " << (connection->player ? connection->player->GetCKey() : "unknown client") << "!"; return false; diff --git a/OSS13 Server/Sources/Player/PlayerCommandsProcessor.cpp b/OSS13 Server/Sources/Player/PlayerCommandsProcessor.cpp index 683b7d6..6b4bb23 100644 --- a/OSS13 Server/Sources/Player/PlayerCommandsProcessor.cpp +++ b/OSS13 Server/Sources/Player/PlayerCommandsProcessor.cpp @@ -32,7 +32,7 @@ void PlayerCommandsProcessor::ProcessCommand(network::protocol::Command &general _REGISTRATE_COMMAND_PROCESSOR(ContextMenuUpdateCommand); _REGISTRATE_COMMAND_PROCESSOR(ContextMenuClickCommand); - LOGE << __FUNCTION__ << ": unknown command (ser id is 0x" << std::hex << generalCommand.Id() << ") was not processed! " + LOGE << __FUNCTION__ << ": unknown command (ser id is 0x" << std::hex << generalCommand.SerID() << ") was not processed! " << "Player: " << player->GetCKey(); } diff --git a/OSS13 Server/Sources/World/Tile.cpp b/OSS13 Server/Sources/World/Tile.cpp index 3738b9b..4efece7 100644 --- a/OSS13 Server/Sources/World/Tile.cpp +++ b/OSS13 Server/Sources/World/Tile.cpp @@ -287,7 +287,7 @@ bool Tile::removeObject(Object *obj) { } void Tile::AddDiff(std::shared_ptr diff, Object *obj) { - EXPECT(uf::CreateSerializableById(diff->Id())); // debug + EXPECT_WITH_MSG(uf::CreateSerializableById(diff->SerID()), "Send unknown diff!"); differencesWithObject.push_back({diff, obj->GetOwnershipPointer()}); } diff --git a/SharedLibrary/Sources/Shared/Network/ISerializable.cpp b/SharedLibrary/Sources/Shared/Network/ISerializable.cpp index 5344c5b..dd31e80 100644 --- a/SharedLibrary/Sources/Shared/Network/ISerializable.cpp +++ b/SharedLibrary/Sources/Shared/Network/ISerializable.cpp @@ -14,7 +14,7 @@ using namespace network::protocol; namespace uf { void ISerializable::Serialize(Archive &archive) { - archive << sf::Int32(Id()); + archive << sf::Int32(SerID()); } #define DECLARE_SER(name) \ diff --git a/SharedLibrary/Sources/Shared/Network/ISerializable.h b/SharedLibrary/Sources/Shared/Network/ISerializable.h index 49ef242..99c7f63 100644 --- a/SharedLibrary/Sources/Shared/Network/ISerializable.h +++ b/SharedLibrary/Sources/Shared/Network/ISerializable.h @@ -6,13 +6,13 @@ #include #include -#define _DEFINE_SERID(id) \ - uint32_t Id() override { \ - constexpr uint32_t _id = id; \ - return _id; \ - } \ - constexpr static uint32_t StaticId() { \ - return id; \ +#define _DEFINE_SERID(id) \ + uint32_t SerID() override { \ + constexpr uint32_t _id = id; \ + return _id; \ + } \ + constexpr static uint32_t StaticSerID() { \ + return id; \ } namespace uf { @@ -21,10 +21,8 @@ class Archive; class ISerializable : public ICopyable { public: - virtual uint32_t Id() = 0; + virtual uint32_t SerID() = 0; virtual void Serialize(Archive &archive); - - virtual ~ISerializable() = default; }; std::unique_ptr CreateSerializableById(uint32_t id); From d4d6760c2e10c85410664b8c516787e53cb65652 Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 01:51:07 +0300 Subject: [PATCH 2/8] refact(archive): pack archive to another archive Also remove InputArchive and OutputArchive --- OSS13 Client/Sources/Network/Connection.cpp | 15 ++-- OSS13 Client/Sources/Network/Connection.h | 2 +- .../Sources/Network/NetworkController.cpp | 15 ++-- .../Sources/Network/NetworkController.hpp | 2 +- .../Sources/Shared/Network/Archive.cpp | 37 ++++----- .../Sources/Shared/Network/Archive.h | 83 ++++++++++++------- .../Shared/Network/ArchiveConverters.cpp | 8 +- .../Shared/Network/ArchiveConverters.h | 6 +- .../Protocol/ServerToClient/WindowData.h | 2 +- 9 files changed, 92 insertions(+), 78 deletions(-) diff --git a/OSS13 Client/Sources/Network/Connection.cpp b/OSS13 Client/Sources/Network/Connection.cpp index 3640c88..2226253 100644 --- a/OSS13 Client/Sources/Network/Connection.cpp +++ b/OSS13 Client/Sources/Network/Connection.cpp @@ -90,10 +90,10 @@ void Connection::session() { sendCommands(); working = true; } - sf::Packet packet; - if (socket.receive(packet) == sf::Socket::Done) { + auto packet = std::make_unique(); + if (socket.receive(*packet) == sf::Socket::Done) { try { - parsePacket(packet); + parsePacket(std::move(packet)); } catch (const std::exception &e) { MANAGE_EXCEPTION(e); } @@ -107,17 +107,16 @@ void Connection::session() { void Connection::sendCommands() { while (!commandQueue.Empty()) { - sf::Packet packet; - uf::InputArchive ar(packet); + uf::Archive ar; Command *temp = commandQueue.Pop(); ar << *temp; if (temp) delete temp; - while (socket.send(packet) == sf::Socket::Partial); + while (socket.send(ar.GetPacket()) == sf::Socket::Partial); } } -bool Connection::parsePacket(sf::Packet &packet) { - uf::OutputArchive ar(packet); +bool Connection::parsePacket(std::unique_ptr packet) { + uf::Archive ar(std::move(packet)); auto serializable = ar.UnpackSerializable(); auto generalCommand = uptr(dynamic_cast(serializable.release())); diff --git a/OSS13 Client/Sources/Network/Connection.h b/OSS13 Client/Sources/Network/Connection.h index 0c8000b..8efa0e9 100644 --- a/OSS13 Client/Sources/Network/Connection.h +++ b/OSS13 Client/Sources/Network/Connection.h @@ -30,7 +30,7 @@ class Connection { private: static void session(); static void sendCommands(); - static bool parsePacket(sf::Packet &); + static bool parsePacket(std::unique_ptr packet); private: static Status status; diff --git a/OSS13 Server/Sources/Network/NetworkController.cpp b/OSS13 Server/Sources/Network/NetworkController.cpp index 6820368..5f11e9a 100644 --- a/OSS13 Server/Sources/Network/NetworkController.cpp +++ b/OSS13 Server/Sources/Network/NetworkController.cpp @@ -67,11 +67,11 @@ void NetworkController::working(std::unique_ptr listener) { sf::TcpSocket *socket = iter->get()->socket.get(); sptr player = (*iter)->player; - sf::Packet packet; - sf::Socket::Status status = socket->receive(packet); + auto packet = std::make_unique(); + sf::Socket::Status status = socket->receive(*packet); switch (status) { case sf::Socket::Done: - if (!parsePacket(packet, *iter)) { + if (!parsePacket(std::move(packet), *iter)) { selector.remove(*socket); iter = connections.erase(iter); continue; @@ -99,20 +99,19 @@ void NetworkController::working(std::unique_ptr listener) { // Sending to client for (auto &connection : connections) { while (!connection->commandsToClient.Empty()) { - sf::Packet packet; - uf::InputArchive ar(packet); + uf::Archive ar; network::protocol::Command *command = connection->commandsToClient.Pop(); EXPECT(command); ar << *command; delete command; - connection->socket->send(packet); + connection->socket->send(ar.GetPacket()); } } } } -bool NetworkController::parsePacket(sf::Packet &packet, sptr &connection) { - uf::OutputArchive ar(packet); +bool NetworkController::parsePacket(std::unique_ptr packet, sptr &connection) { + uf::Archive ar(std::move(packet)); auto serializable = ar.UnpackSerializable(); auto generalCommand = uptr(dynamic_cast(serializable.release())); diff --git a/OSS13 Server/Sources/Network/NetworkController.hpp b/OSS13 Server/Sources/Network/NetworkController.hpp index 2d397dc..ce592dc 100644 --- a/OSS13 Server/Sources/Network/NetworkController.hpp +++ b/OSS13 Server/Sources/Network/NetworkController.hpp @@ -20,7 +20,7 @@ class NetworkController { void working(std::unique_ptr listener); // return false if received "disconnect" packet - bool parsePacket(sf::Packet &, sptr &connection); + bool parsePacket(std::unique_ptr packet, sptr &connection); public: NetworkController(); diff --git a/SharedLibrary/Sources/Shared/Network/Archive.cpp b/SharedLibrary/Sources/Shared/Network/Archive.cpp index 72a7d97..2466ff2 100644 --- a/SharedLibrary/Sources/Shared/Network/Archive.cpp +++ b/SharedLibrary/Sources/Shared/Network/Archive.cpp @@ -6,18 +6,21 @@ using namespace uf; -// Archive - -Archive::Archive(sf::Packet &packet) : - packet(packet) +Archive::Archive() : + mode(Mode::Input), + packet(std::make_unique()) { } -#define DECLARE_SER(name) \ - case #name##_crc32: { uptr p = std::make_unique(); p->Serialize(*this); return p; } +Archive::Archive(std::unique_ptr packet) : + mode(Mode::Output), + packet(std::move(packet)) +{ } uptr Archive::UnpackSerializable() { - sf::Int32 id; - packet >> id; + EXPECT(mode == Mode::Output); + + sf::Int32 id{}; + serializeSimple(id); auto serializable = CreateSerializableById(id); serializable->Serialize(*this); @@ -25,19 +28,7 @@ uptr Archive::UnpackSerializable() { return serializable; } +Archive::Mode Archive::GetMode() const { return mode; } +void Archive::SetMode(Archive::Mode mode) { this->mode = mode; } -// InputArchive - -InputArchive::InputArchive(sf::Packet &packet) : - Archive(packet) -{ - isOut = false; -} - -// OutputArchive - -OutputArchive::OutputArchive(sf::Packet &packet) : - Archive(packet) -{ - isOut = true; -} +sf::Packet &Archive::GetPacket() { return *packet; } diff --git a/SharedLibrary/Sources/Shared/Network/Archive.h b/SharedLibrary/Sources/Shared/Network/Archive.h index 9018ae5..e7eb09d 100644 --- a/SharedLibrary/Sources/Shared/Network/Archive.h +++ b/SharedLibrary/Sources/Shared/Network/Archive.h @@ -4,14 +4,28 @@ #include #include +#include +#include #include namespace uf { -class Archive { +class Archive : public ICopyable { public: - Archive(sf::Packet &packet); - virtual ~Archive() = default; + Archive(); + Archive(std::unique_ptr packet); + + enum class Mode { + Output, + Input + }; + + uptr UnpackSerializable(); + + Mode GetMode() const; + void SetMode(Mode mode); + + sf::Packet &GetPacket(); template Archive &operator&(T &ser) { @@ -19,7 +33,7 @@ class Archive { sf::Int32 id; *this >> id; // we know type, so drop excess id reinterpret_cast(ser).Serialize(*this); } else { - serialize(ser); + serializeSimple(ser); } return *this; @@ -27,59 +41,70 @@ class Archive { template Archive &operator>>(T &ser) { - if (isOut) *this & ser; + if (mode == Mode::Output) *this & ser; return *this; } template Archive &operator<<(const T &ser) { - if (!isOut) *this & const_cast(ser); + if (mode == Mode::Input) *this & const_cast(ser); return *this; } - uptr UnpackSerializable(); - bool IsOutput() { return isOut; } - protected: template - void serialize(T &ser) { - if (isOut) - packet >> ser; + void serializeSimple(T &ser) { + if (mode == Mode::Output) + *packet >> ser; else - packet << ser; + *packet << ser; } template - void serialize(uptr &ser) { - if (isOut) + void serializeSimple(uptr &ser) { + if (mode == Mode::Output) ser.reset(dynamic_cast(this->UnpackSerializable().release())); else reinterpret_cast(ser.get())->Serialize(*this); } template - void serialize(sptr &ser) { - if (isOut) + void serializeSimple(sptr &ser) { + if (mode == Mode::Output) ser.reset(dynamic_cast(this->UnpackSerializable().release())); else reinterpret_cast(ser.get())->Serialize(*this); } + template<> + void serializeSimple(Archive &ser) { + auto lastSetMode = ser.GetMode(); + if (mode == Mode::Output) { + ser.SetMode(Mode::Input); + sf::Int32 size; + *this >> size; + while (size--) { + sf::Int8 byte; + *this >> byte; + ser << byte; + } + } else { + ser.SetMode(Mode::Output); + size_t size = ser.packet->getDataSize(); + *this << sf::Int32(size); + auto *byte = reinterpret_cast(ser.packet->getData()); + for (size_t i = 0; i < size; i++, byte++) { + *this << *byte; + } + } + ser.SetMode(lastSetMode); + } + protected: - bool isOut; + Mode mode; private: - sf::Packet &packet; -}; - -class InputArchive : public Archive { -public: - explicit InputArchive(sf::Packet &packet); -}; - -class OutputArchive : public Archive { -public: - explicit OutputArchive(sf::Packet &packet); + std::unique_ptr packet; }; } diff --git a/SharedLibrary/Sources/Shared/Network/ArchiveConverters.cpp b/SharedLibrary/Sources/Shared/Network/ArchiveConverters.cpp index 8d8bb8a..1ac729e 100644 --- a/SharedLibrary/Sources/Shared/Network/ArchiveConverters.cpp +++ b/SharedLibrary/Sources/Shared/Network/ArchiveConverters.cpp @@ -1,7 +1,7 @@ #include "ArchiveConverters.h" uf::Archive &operator&(uf::Archive &ar, long int &li) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { sf::Int32 buf; ar >> buf; li = buf; @@ -12,7 +12,7 @@ uf::Archive &operator&(uf::Archive &ar, long int &li) { } uf::Archive &operator&(uf::Archive &ar, uf::Direction &d) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { sf::Int8 buf; ar >> buf; d = static_cast(buf); @@ -23,7 +23,7 @@ uf::Archive &operator&(uf::Archive &ar, uf::Direction &d) { } uf::Archive &operator&(uf::Archive &ar, uf::DirectionSet &directionSet) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { auto buf = directionSet.GetBuffer(); ar >> buf; directionSet.SetBuffer(buf); @@ -34,7 +34,7 @@ uf::Archive &operator&(uf::Archive &ar, uf::DirectionSet &directionSet) { } uf::Archive &operator&(uf::Archive &ar, uf::DirectionSetFractional &directionSetFractional) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { std::array buf; ar >> buf; directionSetFractional.SetFractions(std::move(buf)); diff --git a/SharedLibrary/Sources/Shared/Network/ArchiveConverters.h b/SharedLibrary/Sources/Shared/Network/ArchiveConverters.h index e3b4581..3e9d4c0 100644 --- a/SharedLibrary/Sources/Shared/Network/ArchiveConverters.h +++ b/SharedLibrary/Sources/Shared/Network/ArchiveConverters.h @@ -12,7 +12,7 @@ uf::Archive &operator&(uf::Archive &ar, long int &li); template uf::Archive &operator&(uf::Archive &ar, std::vector &vector) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { EXPECT_WITH_MSG(vector.size() == 0, "Try unpack Archive to non-empty vector"); sf::Int32 size; ar >> size; @@ -28,7 +28,7 @@ uf::Archive &operator&(uf::Archive &ar, std::vector &vector) { template uf::Archive &operator&(uf::Archive &ar, std::bitset &set) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { sf::Int32 buffer; ar >> buffer; set = unsigned(buffer); @@ -67,7 +67,7 @@ uf::Archive &operator&(uf::Archive &ar, uf::vec3 &vec) { template uf::Archive &operator&(uf::Archive &ar, std::chrono::duration &duration) { - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { RepType buf; ar >> buf; duration = std::chrono::duration(buf); diff --git a/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WindowData.h b/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WindowData.h index 5a88835..c8e28e4 100644 --- a/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WindowData.h +++ b/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WindowData.h @@ -13,7 +13,7 @@ DEFINE_SERIALIZABLE(WindowData, uf::ISerializable) void Serialize(uf::Archive &ar) override { uf::ISerializable::Serialize(ar); - if (ar.IsOutput()) { + if (ar.GetMode() == uf::Archive::Mode::Output) { sf::Int32 size; ar >> size; for (int i = 0; i < size; i++) From ab6d1b9f10af3aa6854a3a8830ff15b874b1595c Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 02:44:19 +0300 Subject: [PATCH 3/8] feat(syncable): add Syncable Network primitive for classes auto synchronization --- OSS13 Client/OSS13 Client.vcxproj | 8 +- OSS13 Server/OSS13 Server.vcxproj | 4 - SharedLibrary/SharedLibrary.vcxproj | 10 ++ SharedLibrary/SharedLibrary.vcxproj.filters | 6 + .../Sources/Shared/Network/Syncable.cpp | 75 +++++++++++ .../Sources/Shared/Network/Syncable.h | 117 ++++++++++++++++++ .../Network/Syncable/ObjectSyncFields.h | 20 +++ .../Tests/SharedLibrary_Test.vcxproj | 1 + .../Tests/SharedLibrary_Test.vcxproj.filters | 3 + .../Tests/Sources/Syncable_Tests.cpp | 27 ++++ 10 files changed, 263 insertions(+), 8 deletions(-) create mode 100644 SharedLibrary/Sources/Shared/Network/Syncable.cpp create mode 100644 SharedLibrary/Sources/Shared/Network/Syncable.h create mode 100644 SharedLibrary/Sources/Shared/Network/Syncable/ObjectSyncFields.h create mode 100644 SharedLibrary/Tests/Sources/Syncable_Tests.cpp diff --git a/OSS13 Client/OSS13 Client.vcxproj b/OSS13 Client/OSS13 Client.vcxproj index f8ac7e4..9214260 100644 --- a/OSS13 Client/OSS13 Client.vcxproj +++ b/OSS13 Client/OSS13 Client.vcxproj @@ -77,7 +77,7 @@ /ignore:4099 %(AdditionalOptions) - opengl32.lib;winmm.lib;ws2_32.lib;%(AdditionalDependencies) + opengl32.lib;%(AdditionalDependencies) mainCRTStartup Windows @@ -88,7 +88,7 @@ /ignore:4099 %(AdditionalOptions) - opengl32.lib;winmm.lib;ws2_32.lib;%(AdditionalDependencies) + opengl32.lib;%(AdditionalDependencies) mainCRTStartup Windows @@ -102,7 +102,7 @@ true true - opengl32.lib;winmm.lib;ws2_32.lib;%(AdditionalDependencies) + opengl32.lib;%(AdditionalDependencies) mainCRTStartup Windows @@ -116,7 +116,7 @@ true true - opengl32.lib;winmm.lib;ws2_32.lib;%(AdditionalDependencies) + opengl32.lib;%(AdditionalDependencies) mainCRTStartup Windows diff --git a/OSS13 Server/OSS13 Server.vcxproj b/OSS13 Server/OSS13 Server.vcxproj index 4ebe66c..d40b6ad 100644 --- a/OSS13 Server/OSS13 Server.vcxproj +++ b/OSS13 Server/OSS13 Server.vcxproj @@ -80,7 +80,6 @@ true /ignore:4099 %(AdditionalOptions) - winmm.lib;ws2_32.lib;%(AdditionalDependencies) Console @@ -93,7 +92,6 @@ true /ignore:4099 %(AdditionalOptions) - winmm.lib;ws2_32.lib;%(AdditionalDependencies) Console @@ -107,7 +105,6 @@ true true true - winmm.lib;ws2_32.lib;%(AdditionalDependencies) Console @@ -121,7 +118,6 @@ true true true - winmm.lib;ws2_32.lib;%(AdditionalDependencies) Console diff --git a/SharedLibrary/SharedLibrary.vcxproj b/SharedLibrary/SharedLibrary.vcxproj index d6e0026..583b6ac 100644 --- a/SharedLibrary/SharedLibrary.vcxproj +++ b/SharedLibrary/SharedLibrary.vcxproj @@ -36,6 +36,7 @@ + @@ -84,6 +85,7 @@ + @@ -160,6 +162,9 @@ Windows + + winmm.lib;ws2_32.lib; + @@ -176,6 +181,7 @@ /ignore:4006 /ignore:4221 %(AdditionalOptions) + winmm.lib;ws2_32.lib; @@ -197,6 +203,9 @@ true + + winmm.lib;ws2_32.lib; + @@ -218,6 +227,7 @@ /ignore:4006 /ignore:4221 %(AdditionalOptions) + winmm.lib;ws2_32.lib; diff --git a/SharedLibrary/SharedLibrary.vcxproj.filters b/SharedLibrary/SharedLibrary.vcxproj.filters index 274aa63..16bf7d9 100644 --- a/SharedLibrary/SharedLibrary.vcxproj.filters +++ b/SharedLibrary/SharedLibrary.vcxproj.filters @@ -125,6 +125,9 @@ Файлы исходного кода + + Файлы исходного кода + @@ -265,5 +268,8 @@ Заголовочные файлы + + Заголовочные файлы + \ No newline at end of file diff --git a/SharedLibrary/Sources/Shared/Network/Syncable.cpp b/SharedLibrary/Sources/Shared/Network/Syncable.cpp new file mode 100644 index 0000000..bf502e2 --- /dev/null +++ b/SharedLibrary/Sources/Shared/Network/Syncable.cpp @@ -0,0 +1,75 @@ +#include "Syncable.h" + +namespace uf { + +namespace detail { + +void GeneralSyncField::setChanged() { changed = true; syncable->changed = true; } + + +} // namespace detail + +SyncableChanges Syncable::GetChanges() { + SyncableChanges changes; + changes.archive.SetMode(Archive::Mode::Input); + std::size_t changedCount = 0; + for (std::size_t i = 0; i < fieldsOffsets.size(); i++) { + if (getField(i)->changed) + changedCount++; + } + EXPECT_WITH_MSG(changedCount, "Empty SyncableChanges are created!"); + changes.archive << sf::Int32(changedCount); + + for (std::size_t i = 0; i < fieldsOffsets.size(); i++) { + if (getField(i)->changed) { + changes.archive << sf::Int32(i); + getField(i)->Serialize(changes.archive); + } + } + return changes; +} + +void Syncable::AmendChanges(SyncableChanges &&changes) { + changes.archive.SetMode(Archive::Mode::Output); + sf::Int32 changedCount; + changes.archive >> changedCount; + do { + sf::Int32 fieldNumber; + changes.archive >> fieldNumber; + changes.archive >> *getField(std::size_t(fieldNumber)); + } while (--changedCount); +} + +void Syncable::DropUpdateState() { + for (std::size_t i = 0; i < fieldsOffsets.size(); i++) + getField(i)->changed = false; + changed = false; +} + +bool Syncable::IsChanged() { + bool t = false; + for (std::size_t i = 0; i < fieldsOffsets.size(); i++) { + if (getField(i)->changed) + t = true; + } + EXPECT(t || !changed); + return changed; +} + +void Syncable::Serialize(Archive &ar) { + uf::ISerializable::Serialize(ar); + for (std::size_t i = 0; i < fieldsOffsets.size(); i++) { + ar & *getField(i); + } +} + +void Syncable::registrateField(std::ptrdiff_t fieldOffset) { + fieldsOffsets.push_back(fieldOffset); + getField(fieldsOffsets.size() - 1)->syncable = this; +} + +detail::GeneralSyncField *Syncable::getField(size_t index) { + return reinterpret_cast(size_t(this) + fieldsOffsets[index]); +} + +} // namespace uf diff --git a/SharedLibrary/Sources/Shared/Network/Syncable.h b/SharedLibrary/Sources/Shared/Network/Syncable.h new file mode 100644 index 0000000..e8c22ed --- /dev/null +++ b/SharedLibrary/Sources/Shared/Network/Syncable.h @@ -0,0 +1,117 @@ +#pragma once + +#include + +#include +#include + +namespace uf { + +struct Syncable; + +namespace detail { + +template +std::ptrdiff_t memberOffset(U T::* member) +{ + return reinterpret_cast( + &(reinterpret_cast(NULL)->*member) + ); +} + +DEFINE_SERIALIZABLE(GeneralSyncField, uf::ISerializable) + friend Syncable; +public: + GeneralSyncField() = default; + ~GeneralSyncField() override = default; + GeneralSyncField(const GeneralSyncField &other) : changed(other.changed) { } + GeneralSyncField &operator=(const GeneralSyncField &other) { this->changed = other.changed; return *this; } + GeneralSyncField(GeneralSyncField &&other) : changed(std::move(other.changed)) { } + GeneralSyncField &operator=(GeneralSyncField &&other) { this->changed = std::move(other.changed); return *this; } + +protected: + void setChanged(); + +private: + bool changed{false}; + Syncable *syncable{}; +DEFINE_SERIALIZABLE_END + +} // namespace detail + +template +struct SyncField : public detail::GeneralSyncField { + friend Syncable; +public: + SyncField &operator=(const T &value) { this->value = value; setChanged(); return *this; } + operator const T &() const { return value; } + + T &GetValue() { return value; }; + + void Serialize(Archive &ar) final { + uf::ISerializable::Serialize(ar); + ar & value; + if (ar.GetMode() == uf::Archive::Mode::Output) + setChanged(); + } + +private: + T value{}; +}; + +DEFINE_SERIALIZABLE(SyncableChanges, uf::ISerializable) + friend Syncable; + + void Serialize(Archive &ar) override { + uf::ISerializable::Serialize(ar); + ar & archive; + } + +protected: + uf::Archive archive; +DEFINE_SERIALIZABLE_END + +struct Syncable : public uf::ISerializable { + friend detail::GeneralSyncField; + + SyncableChanges GetChanges(); + void AmendChanges(SyncableChanges &&changes); + + void DropUpdateState(); + bool IsChanged(); + + void Serialize(Archive &ar) final; + +protected: + void registrateField(std::ptrdiff_t fieldOffset); + +private: + detail::GeneralSyncField *getField(size_t index); + +private: + bool changed{false}; + std::vector fieldsOffsets; +}; + +} // namespace uf + +/* + Start of Syncable structure definition + + Declare all fields in Syncable constructor with DECLARE_SYNCABLE_FIELD macro. +*/ +#define DEFINE_SYNCABLE(TypeName) \ + DEFINE_SERIALIZABLE(TypeName, uf::Syncable) \ + TypeName(const TypeName &other) { TypeName(); *this = other; }; \ + TypeName &operator=(const TypeName &other) = default; \ + TypeName(TypeName &&other) { TypeName(); *this = std::move(other); }; \ + TypeName &operator=(TypeName &&other) = default; \ + +/* + End of Syncable structure definition +*/ +#define DEFINE_SYNCABLE_END \ + DEFINE_SERIALIZABLE_END + +#define DECLARE_SYNCABLE_FIELD(field) \ + registrateField(uf::detail::memberOffset(field)); diff --git a/SharedLibrary/Sources/Shared/Network/Syncable/ObjectSyncFields.h b/SharedLibrary/Sources/Shared/Network/Syncable/ObjectSyncFields.h new file mode 100644 index 0000000..1e818e6 --- /dev/null +++ b/SharedLibrary/Sources/Shared/Network/Syncable/ObjectSyncFields.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +namespace network { +namespace sync { + +DEFINE_SYNCABLE(ObjectSyncFields) +protected: + uf::SyncField name; + +public: + ObjectSyncFields() { + DECLARE_SYNCABLE_FIELD(&ObjectSyncFields::name); + }; +DEFINE_SYNCABLE_END + +} // namespace sync +} // namespace network diff --git a/SharedLibrary/Tests/SharedLibrary_Test.vcxproj b/SharedLibrary/Tests/SharedLibrary_Test.vcxproj index aa8c0d1..38e6c23 100644 --- a/SharedLibrary/Tests/SharedLibrary_Test.vcxproj +++ b/SharedLibrary/Tests/SharedLibrary_Test.vcxproj @@ -151,6 +151,7 @@ + diff --git a/SharedLibrary/Tests/SharedLibrary_Test.vcxproj.filters b/SharedLibrary/Tests/SharedLibrary_Test.vcxproj.filters index e52ea42..55df370 100644 --- a/SharedLibrary/Tests/SharedLibrary_Test.vcxproj.filters +++ b/SharedLibrary/Tests/SharedLibrary_Test.vcxproj.filters @@ -21,5 +21,8 @@ Source Files + + Source Files + \ No newline at end of file diff --git a/SharedLibrary/Tests/Sources/Syncable_Tests.cpp b/SharedLibrary/Tests/Sources/Syncable_Tests.cpp new file mode 100644 index 0000000..cc78dc8 --- /dev/null +++ b/SharedLibrary/Tests/Sources/Syncable_Tests.cpp @@ -0,0 +1,27 @@ +#include + +#include + +DEFINE_SYNCABLE(TestSyncable) + uf::SyncField a; + uf::SyncField b; + + TestSyncable() { + DECLARE_SYNCABLE_FIELD(&TestSyncable::a); + DECLARE_SYNCABLE_FIELD(&TestSyncable::b); + } +DEFINE_SYNCABLE_END + +TEST(Syncable, test) { + TestSyncable testSyncable; + testSyncable.a = 12345; + testSyncable.b = "test string"; + + auto changes = testSyncable.GetChanges(); + + TestSyncable otherSyncable; + otherSyncable.AmendChanges(std::move(changes)); + + CHECK(testSyncable.a.GetValue() == otherSyncable.a.GetValue()); + CHECK(testSyncable.b.GetValue() == otherSyncable.b.GetValue()); +} From 7198a37592f43173b92d2423197c581f339585ea Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 03:11:58 +0300 Subject: [PATCH 4/8] [SRV] fix(ScriptEngine): don't bind VerbsHolder KRUTCH D: I will refactor this later --- GameLogic/Engine/Server.py | 16 ++++++- GameLogic/Engine/World.py | 45 ++++++------------- .../ScriptEngine/Module/ServerModule.cpp | 5 +-- .../ScriptEngine/Module/WorldModule.cpp | 6 +-- 4 files changed, 31 insertions(+), 41 deletions(-) diff --git a/GameLogic/Engine/Server.py b/GameLogic/Engine/Server.py index aa8c779..53d5be5 100644 --- a/GameLogic/Engine/Server.py +++ b/GameLogic/Engine/Server.py @@ -28,7 +28,7 @@ def __init__(self, impl): def world() -> Engine.World.World: return Engine.World.World(eGGame.world) -class Player(ePlayer, Engine.World.VerbsHolder): +class Player(ePlayer): """ Player class is persistent until restart. When player re-logins, existed Player instance is used. @@ -47,10 +47,18 @@ class Player(ePlayer, Engine.World.VerbsHolder): IsConnected() -> bool returns True when player is online + AddVerb(name: str, action: Callable[[Player], None]) + add new verb + + Parametres + ---------- + name: str + verb's key. Use name to call verb from console + """ def __init__(self, impl): - Engine.World.VerbsHolder.__init__(self, impl) + self._impl = impl @property def ckey(self) -> str: @@ -66,6 +74,10 @@ def control(self, value: Engine.World.Control): def IsConnected(self) -> bool: return self._impl.IsConnected() + def AddVerb(self, name: str, action: Callable[[Engine.Server.Player], None]): + wrapper = lambda player: action(Engine.Server.Player(player)) + self._impl.AddVerb(name, wrapper) + class ResourceManager(eResourceManager): """ diff --git a/GameLogic/Engine/World.py b/GameLogic/Engine/World.py index 3cdda0d..522a2ef 100644 --- a/GameLogic/Engine/World.py +++ b/GameLogic/Engine/World.py @@ -125,37 +125,7 @@ def GetDenseObject(self, directions: DirectionSet) -> Object: return self._impl.GetDenseObject(directions._impl) -class VerbsHolder(eVerbsHolder): - """ - Inheritance from this class allow to define special actions without - arguments which can be called with command from console - - VerbsHolder is registrated with unique name, so player can call it's verbs. - - For example, class Player registrated with name "Player". - So player's verb "Drop" can be called with next command: "Player.Drop" - - Methods - ------- - AddVerb(name: str, action: Callable[[Player], None]) - add new verb - - Parametres - ---------- - name: str - verb's key. Use name to call verb from console - - """ - - def __init__(self, impl): - self._impl = impl - - def AddVerb(self, name: str, action: Callable[[Engine.Server.Player], None]): - wrapper = lambda player: action(Engine.Server.Player(player)) - eVerbsHolder.AddVerb(self._impl, name, wrapper) - - -class Object(eObject, VerbsHolder): +class Object(eObject): """ Any game object @@ -313,6 +283,14 @@ class Object(eObject, VerbsHolder): Note: "animation" is animated sprite. Thus "id" is sprite id. + AddVerb(name: str, action: Callable[[Player], None]) + add new verb + + Parametres + ---------- + name: str + verb's key. Use name to call verb from console + Delete(self): delete object @@ -343,7 +321,6 @@ class Object(eObject, VerbsHolder): def __init__(self): eObject.__init__(self) - VerbsHolder.__init__(self, self) self.name = str(self.defName) self.sprite = str(self.defSprite) self.description = str(self.defDescription) @@ -490,6 +467,10 @@ def SetSpriteState(self, state: ItemSpriteState): def PlayAnimation(self, id: str, callback: Callable[[], None] = None) -> bool: return super().PlayAnimation(id, callback) + def AddVerb(self, name: str, action: Callable[[Engine.Server.Player], None]): + wrapper = lambda player: action(Engine.Server.Player(player)) + super().AddVerb(name, wrapper) + def Delete(self): super().Delete() diff --git a/OSS13 Server/Sources/ScriptEngine/Module/ServerModule.cpp b/OSS13 Server/Sources/ScriptEngine/Module/ServerModule.cpp index cfd6d17..f1d3834 100644 --- a/OSS13 Server/Sources/ScriptEngine/Module/ServerModule.cpp +++ b/OSS13 Server/Sources/ScriptEngine/Module/ServerModule.cpp @@ -26,11 +26,10 @@ PYBIND11_EMBEDDED_MODULE(Engine_Server, m) { .def("AddDelayedActivity", &Game::AddDelayedActivity); m.attr("eGGame") = GGame; - py::object verbsHolder = (py::object) py::module::import("Engine_World").attr("eVerbsHolder"); - - py::class_(m, "ePlayer", verbsHolder) + py::class_(m, "ePlayer") .def_property_readonly("ckey", &Player::GetCKey) .def_property("control", &Player::GetControl, &Player::SetControl, "", py::return_value_policy::reference) + .def("AddVerb", &Object::AddVerb) .def("IsConnected", &Player::IsConnected); py::class_(m, "eResourceManager") diff --git a/OSS13 Server/Sources/ScriptEngine/Module/WorldModule.cpp b/OSS13 Server/Sources/ScriptEngine/Module/WorldModule.cpp index f2f0d6b..84ecfb0 100644 --- a/OSS13 Server/Sources/ScriptEngine/Module/WorldModule.cpp +++ b/OSS13 Server/Sources/ScriptEngine/Module/WorldModule.cpp @@ -38,12 +38,9 @@ PYBIND11_EMBEDDED_MODULE(Engine_World, m) { .def("IsSpace", &Tile::IsSpace) .def("GetDenseObject", &Tile::GetDenseObject, py::return_value_policy::reference); - py::class_ verbsHolder(m, "eVerbsHolder"); - verbsHolder.def("AddVerb", &VerbsHolder::AddVerb); - m.def("eCreateObject", &CreateObject); - py::class_>(m, "eObject", verbsHolder) + py::class_>(m, "eObject", py::multiple_inheritance()) .def(py::init<>()) .def_property("name", &Object::GetName, &Object::SetName) .def_property("sprite", &Object::GetSprite, &Object::SetSprite) @@ -60,6 +57,7 @@ PYBIND11_EMBEDDED_MODULE(Engine_World, m) { .def_property("moveSpeed", &Object::GetMoveSpeed, &Object::SetMoveSpeed) .def_property("isFloor", &Object::IsFloor, &Object::SetIsFloor) .def_property("isWall", &Object::IsWall, &Object::SetIsWall) + .def("AddVerb", &Object::AddVerb) .def("Update", &Object::Update) .def("InteractedBy", &Object::InteractedBy) .def("IsCloseTo", &Object::IsCloseTo) From 7b858e52f2280feb0c86d2312efafe5d86580431 Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 03:26:25 +0300 Subject: [PATCH 5/8] feat(object): make Object Syncable Make Object::name field to be autosyncable --- .../Sources/Graphics/TileGrid/Object.cpp | 5 ++-- .../Sources/Graphics/TileGrid/Object.hpp | 6 ++-- .../Sources/Graphics/TileGrid/Tile.cpp | 10 ++++--- .../Sources/Graphics/TileGrid/Tile.hpp | 2 +- .../Sources/Graphics/TileGrid/TileGrid.cpp | 7 +++++ .../Sources/Graphics/TileGrid/TileGrid.hpp | 2 ++ .../Sources/Network/SyncCommandsProcessor.cpp | 6 ++-- OSS13 Server/Sources/World/Objects/Object.cpp | 29 +++++++++++------- OSS13 Server/Sources/World/Objects/Object.hpp | 4 +-- OSS13 Server/Sources/World/Tile.cpp | 16 ++++++++-- OSS13 Server/Sources/World/World.cpp | 10 +++++++ SharedLibrary/SharedLibrary.vcxproj | 1 + SharedLibrary/SharedLibrary.vcxproj.filters | 3 ++ .../Sources/Shared/Network/ISerializable.cpp | 1 + .../Network/Protocol/ServerToClient/Diff.h | 30 ++++++++++++------- .../Protocol/ServerToClient/WorldInfo.h | 5 ++-- 16 files changed, 99 insertions(+), 38 deletions(-) diff --git a/OSS13 Client/Sources/Graphics/TileGrid/Object.cpp b/OSS13 Client/Sources/Graphics/TileGrid/Object.cpp index 2041310..c8e7e4b 100644 --- a/OSS13 Client/Sources/Graphics/TileGrid/Object.cpp +++ b/OSS13 Client/Sources/Graphics/TileGrid/Object.cpp @@ -10,13 +10,14 @@ #include #include -Object::Object(const network::protocol::ObjectInfo &objectInfo) { +Object::Object(network::protocol::ObjectInfo &&objectInfo) { for (auto &sprite : objectInfo.spriteIds) { AddSprite(uint(sprite)); } + static_cast(*this) = std::move(objectInfo.fields); + id = objectInfo.id; - name = objectInfo.name; layer = objectInfo.layer; direction = objectInfo.direction; density = objectInfo.density; diff --git a/OSS13 Client/Sources/Graphics/TileGrid/Object.hpp b/OSS13 Client/Sources/Graphics/TileGrid/Object.hpp index a2e57f8..0837f01 100644 --- a/OSS13 Client/Sources/Graphics/TileGrid/Object.hpp +++ b/OSS13 Client/Sources/Graphics/TileGrid/Object.hpp @@ -10,6 +10,7 @@ #include #include #include +#include class Sprite; class Tile; @@ -22,9 +23,9 @@ namespace sf { #include "iostream" -class Object { +class Object : public network::sync::ObjectSyncFields { public: - explicit Object(const network::protocol::ObjectInfo &objectInfo); + explicit Object(network::protocol::ObjectInfo &&objectInfo); Object &operator=(Object &) = default; ~Object(); @@ -62,7 +63,6 @@ class Object { private: uint id{}; - std::string name; std::vector<::Sprite> sprites; ::Sprite animation; bool animationProcess{}; diff --git a/OSS13 Client/Sources/Graphics/TileGrid/Tile.cpp b/OSS13 Client/Sources/Graphics/TileGrid/Tile.cpp index 95da6c0..8cedeff 100644 --- a/OSS13 Client/Sources/Graphics/TileGrid/Tile.cpp +++ b/OSS13 Client/Sources/Graphics/TileGrid/Tile.cpp @@ -15,7 +15,7 @@ Tile::Tile(TileGrid *tileGrid) : overlay.setCharacterSize(10); } -Tile::Tile(TileGrid *tileGrid, const network::protocol::TileInfo &tileInfo) : +Tile::Tile(TileGrid *tileGrid, network::protocol::TileInfo &&tileInfo) : Tile(tileGrid) { sprite = CC::Get()->RM.CreateSprite(uint(tileInfo.sprite)); @@ -23,12 +23,14 @@ Tile::Tile(TileGrid *tileGrid, const network::protocol::TileInfo &tileInfo) : for (auto &objInfo : tileInfo.content) { auto &objects = GetTileGrid()->GetObjects(); - auto iter = objects.find(objInfo.id); + auto id = objInfo.id; + + auto iter = objects.find(id); if (iter == objects.end()) { - objects[objInfo.id] = std::make_unique(objInfo); + objects[id] = std::make_unique(std::forward(objInfo)); } - AddObject(objects[objInfo.id].get()); + AddObject(objects[id].get()); } Resize(GetTileGrid()->GetTileSize()); } diff --git a/OSS13 Client/Sources/Graphics/TileGrid/Tile.hpp b/OSS13 Client/Sources/Graphics/TileGrid/Tile.hpp index e7d9710..468dd14 100644 --- a/OSS13 Client/Sources/Graphics/TileGrid/Tile.hpp +++ b/OSS13 Client/Sources/Graphics/TileGrid/Tile.hpp @@ -20,7 +20,7 @@ namespace sf { class Tile : public INonCopyable { public: explicit Tile(TileGrid *tileGrid); - Tile(TileGrid *tileGrid, const network::protocol::TileInfo &tileInfo); + Tile(TileGrid *tileGrid, network::protocol::TileInfo &&tileInfo); Tile(Tile &&) = default; Tile &operator=(Tile &&) = default; ~Tile(); diff --git a/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.cpp b/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.cpp index d7d0c5d..ff69596 100644 --- a/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.cpp +++ b/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.cpp @@ -356,6 +356,13 @@ void TileGrid::RemoveObject(uint id) { LOGE << "Error: object with id " << id << " doesn't exist (TileGrid::RemoveObject)"; } +void TileGrid::AmendObjectChanges(network::protocol::FieldsDiff &&diff) { + auto iter = objects.find(diff.objId); + EXPECT(iter != objects.end()); + auto &obj = iter->second; + obj->AmendChanges(std::forward(diff.fieldsChanges)); +} + void TileGrid::RelocateObject(uint id, apos toVec, int toObjectNum) { Tile *tile = GetTileAbs(toVec); if (!tile) { diff --git a/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.hpp b/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.hpp index 5548acf..e8c2e17 100644 --- a/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.hpp +++ b/OSS13 Client/Sources/Graphics/TileGrid/TileGrid.hpp @@ -10,6 +10,7 @@ #include #include +#include #include @@ -40,6 +41,7 @@ class TileGrid : public Container { // Differences commiting void AddObject(Object *object); void RemoveObject(uint id); + void AmendObjectChanges(network::protocol::FieldsDiff &&diff); void RelocateObject(uint id, apos toVec, int toObjectNum); void SetMoveIntentObject(uint id, uf::Direction direction); void MoveObject(uint id, uf::Direction direction, float speed); diff --git a/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp b/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp index 5647ba4..710ba92 100644 --- a/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp +++ b/OSS13 Client/Sources/Network/SyncCommandsProcessor.cpp @@ -65,7 +65,7 @@ void SyncCommandsProcessor::commandProcessor_GraphicsUpdateCommand(network::prot tileGrid->ShiftBlocks(command.firstTile); for (auto &tileInfo : command.tilesInfo) { - tileGrid->SetBlock(tileInfo.coords, std::make_shared(tileGrid, tileInfo)); + tileGrid->SetBlock(tileInfo.coords, std::make_shared(tileGrid, std::move(tileInfo))); } } if (command.options & server::GraphicsUpdateCommand::Option::CAMERA_MOVE) { @@ -74,11 +74,13 @@ void SyncCommandsProcessor::commandProcessor_GraphicsUpdateCommand(network::prot if (command.options & server::GraphicsUpdateCommand::Option::DIFFERENCES) { for (auto &generalDiff : command.diffs) { if (auto *diff = dynamic_cast(generalDiff.get())) { - auto obj = std::make_unique(diff->objectInfo); + auto obj = std::make_unique(std::move(diff->objectInfo)); tileGrid->AddObject(obj.release()); tileGrid->RelocateObject(diff->objId, diff->coords, diff->layer); } else if (auto *diff = dynamic_cast(generalDiff.get())) { tileGrid->RemoveObject(diff->objId); + } else if (auto *diff = dynamic_cast(generalDiff.get())) { + tileGrid->AmendObjectChanges(std::forward(*diff)); } else if (auto *diff = dynamic_cast(generalDiff.get())) { tileGrid->RelocateObject(diff->objId, diff->newCoords, diff->layer); } else if (auto *diff = dynamic_cast(generalDiff.get())) { diff --git a/OSS13 Server/Sources/World/Objects/Object.cpp b/OSS13 Server/Sources/World/Objects/Object.cpp index 567edf6..c4e1bc5 100644 --- a/OSS13 Server/Sources/World/Objects/Object.cpp +++ b/OSS13 Server/Sources/World/Objects/Object.cpp @@ -146,6 +146,7 @@ void Object::AddObject(Object *obj) { return; } else if (obj->GetTile()) obj->GetTile()->RemoveObject(obj); + obj->DropUpdateState(); content.push_back(obj); obj->holder = this; @@ -155,16 +156,24 @@ void Object::AddObject(Object *obj) { } bool Object::RemoveObject(Object *obj) { - for (auto iter = content.begin(); iter != content.end(); iter++) { - if (*iter == obj) { - obj->setTile(nullptr); - obj->holder = nullptr; - content.erase(iter); + for (auto iter = content.begin(); iter != content.end(); iter++) { + if (*iter == obj) { + if (obj->IsChanged()) { + auto fieldsDiff = std::make_shared(); + fieldsDiff->objId = obj->ID(); + fieldsDiff->fieldsChanges = obj->GetChanges(); + GetTile()->AddDiff(std::move(fieldsDiff), obj); + } + obj->DropUpdateState(); + + obj->setTile(nullptr); + obj->holder = nullptr; + content.erase(iter); askToUpdateIcons(); - return true; - } - } - return false; + return true; + } + } + return false; } void Object::Delete() { @@ -316,7 +325,7 @@ void Object::SetIsWall(bool value) { isWall = value; } network::protocol::ObjectInfo Object::GetObjectInfo() const { network::protocol::ObjectInfo objectInfo; objectInfo.id = id; - objectInfo.name = name; + objectInfo.fields = *this; objectInfo.layer = layer; objectInfo.direction = direction; objectInfo.density = density; diff --git a/OSS13 Server/Sources/World/Objects/Object.hpp b/OSS13 Server/Sources/World/Objects/Object.hpp index 09b1781..171d6a5 100644 --- a/OSS13 Server/Sources/World/Objects/Object.hpp +++ b/OSS13 Server/Sources/World/Objects/Object.hpp @@ -14,12 +14,13 @@ #include #include #include +#include #include class ObjectHolder; class Tile; -class Object : public VerbsHolder, public INonCopyable { +class Object : public network::sync::ObjectSyncFields, public VerbsHolder, public INonCopyable { friend ObjectHolder; friend Tile; @@ -128,7 +129,6 @@ class Object : public VerbsHolder, public INonCopyable { void setTile(Tile *); protected: - std::string name; bool movable; std::string sprite; Global::ItemSpriteState spriteState; // TODO: move it to Item? Also there is need to reimplement packing??? diff --git a/OSS13 Server/Sources/World/Tile.cpp b/OSS13 Server/Sources/World/Tile.cpp index 4efece7..bc86e28 100644 --- a/OSS13 Server/Sources/World/Tile.cpp +++ b/OSS13 Server/Sources/World/Tile.cpp @@ -90,6 +90,13 @@ void Tile::CheckLocale() { } bool Tile::RemoveObject(Object *obj) { + if (obj->IsChanged()) { + auto fieldsDiff = std::make_shared(); + fieldsDiff->objId = obj->ID(); + fieldsDiff->fieldsChanges = obj->GetChanges(); + AddDiff(std::move(fieldsDiff), obj); + } + obj->DropUpdateState(); if (removeObject(obj)) { auto diff = std::make_shared(); diff->objId = obj->ID(); @@ -182,14 +189,19 @@ void Tile::PlaceTo(Object *obj) { CheckLocale(); } - auto objInfo = obj->GetObjectInfo(); - if (lastTile) { + if (obj->IsChanged()) { + auto fieldsDiff = std::make_shared(); + fieldsDiff->objId = obj->ID(); + fieldsDiff->fieldsChanges = obj->GetChanges(); + lastTile->AddDiff(std::move(fieldsDiff), obj); + } auto relocateAwayDiff = std::make_shared(); relocateAwayDiff->objId = obj->ID(); relocateAwayDiff->newCoords = pos; lastTile->AddDiff(relocateAwayDiff, obj); } + obj->DropUpdateState(); addObject(obj); auto relocateDiff = std::make_shared(); diff --git a/OSS13 Server/Sources/World/World.cpp b/OSS13 Server/Sources/World/World.cpp index 65f4909..ce643fb 100644 --- a/OSS13 Server/Sources/World/World.cpp +++ b/OSS13 Server/Sources/World/World.cpp @@ -53,6 +53,16 @@ void World::Update(std::chrono::microseconds timeElapsed) { continue; objects[i]->Update(timeElapsed); } + + for (auto &object : objects) { + if (object && object->GetTile() && object->IsChanged()) { + auto diff = std::make_shared(); + diff->objId = object->ID(); + diff->fieldsChanges = object->GetChanges(); + object->GetTile()->AddDiff(std::move(diff), object.get()); + object->DropUpdateState(); + } + } } void World::CreateTestItems() { diff --git a/SharedLibrary/SharedLibrary.vcxproj b/SharedLibrary/SharedLibrary.vcxproj index 583b6ac..6c65f48 100644 --- a/SharedLibrary/SharedLibrary.vcxproj +++ b/SharedLibrary/SharedLibrary.vcxproj @@ -86,6 +86,7 @@ + diff --git a/SharedLibrary/SharedLibrary.vcxproj.filters b/SharedLibrary/SharedLibrary.vcxproj.filters index 16bf7d9..ac0aeaf 100644 --- a/SharedLibrary/SharedLibrary.vcxproj.filters +++ b/SharedLibrary/SharedLibrary.vcxproj.filters @@ -271,5 +271,8 @@ Заголовочные файлы + + Заголовочные файлы + \ No newline at end of file diff --git a/SharedLibrary/Sources/Shared/Network/ISerializable.cpp b/SharedLibrary/Sources/Shared/Network/ISerializable.cpp index dd31e80..e7d4f83 100644 --- a/SharedLibrary/Sources/Shared/Network/ISerializable.cpp +++ b/SharedLibrary/Sources/Shared/Network/ISerializable.cpp @@ -75,6 +75,7 @@ std::unique_ptr CreateSerializableById(uint32_t id) { DECLARE_SER(RelocateAwayDiff) DECLARE_SER(AddDiff) DECLARE_SER(RemoveDiff) + DECLARE_SER(FieldsDiff) DECLARE_SER(MoveIntentDiff) DECLARE_SER(MoveDiff) DECLARE_SER(UpdateIconsDiff) diff --git a/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/Diff.h b/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/Diff.h index 6ef6304..97bc679 100644 --- a/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/Diff.h +++ b/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/Diff.h @@ -4,6 +4,7 @@ #include #include +#include #include namespace network { @@ -27,31 +28,40 @@ DEFINE_SERIALIZABLE(Diff, uf::ISerializable) static uint32_t diffCounter; DEFINE_SERIALIZABLE_END -DEFINE_SERIALIZABLE(RelocateDiff, Diff) - uf::vec3i newCoords; +DEFINE_SERIALIZABLE(AddDiff, Diff) + ObjectInfo objectInfo; + uf::vec3i coords; uint32_t layer; void Serialize(uf::Archive &ar) override { Diff::Serialize(ar); - ar & newCoords; + ar & objectInfo; + ar & coords; ar & layer; } DEFINE_SERIALIZABLE_END -DEFINE_PURE_SERIALIZABLE(RelocateAwayDiff, RelocateDiff) +DEFINE_PURE_SERIALIZABLE(RemoveDiff, Diff) + +DEFINE_SERIALIZABLE(FieldsDiff, Diff) + uf::SyncableChanges fieldsChanges; -DEFINE_SERIALIZABLE(AddDiff, Diff) - ObjectInfo objectInfo; - uf::vec3i coords; + void Serialize(uf::Archive &ar) override { + Diff::Serialize(ar); + ar & fieldsChanges; + } +DEFINE_SERIALIZABLE_END + +DEFINE_SERIALIZABLE(RelocateDiff, Diff) + uf::vec3i newCoords; uint32_t layer; void Serialize(uf::Archive &ar) override { Diff::Serialize(ar); - ar & objectInfo; - ar & coords; + ar & newCoords; ar & layer; } DEFINE_SERIALIZABLE_END -DEFINE_PURE_SERIALIZABLE(RemoveDiff, Diff) +DEFINE_PURE_SERIALIZABLE(RelocateAwayDiff, RelocateDiff) DEFINE_SERIALIZABLE(MoveIntentDiff, Diff) uf::Direction direction; diff --git a/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WorldInfo.h b/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WorldInfo.h index d953361..0459b65 100644 --- a/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WorldInfo.h +++ b/SharedLibrary/Sources/Shared/Network/Protocol/ServerToClient/WorldInfo.h @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -28,7 +29,7 @@ DEFINE_SERIALIZABLE_END DEFINE_SERIALIZABLE(ObjectInfo, uf::ISerializable) uint32_t id; - std::string name; + sync::ObjectSyncFields fields; std::vector spriteIds; uint32_t layer; uf::Direction direction; @@ -42,7 +43,7 @@ DEFINE_SERIALIZABLE(ObjectInfo, uf::ISerializable) void Serialize(uf::Archive &ar) override { uf::ISerializable::Serialize(ar); ar & id; - ar & name; + ar & fields; ar & spriteIds; ar & layer; ar & direction; From cfd49509233ef935430534f2e44898b13ad617a7 Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 15:22:59 +0300 Subject: [PATCH 6/8] fix(archive): fix GCC compile --- SharedLibrary/Sources/Shared/Network/Archive.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SharedLibrary/Sources/Shared/Network/Archive.h b/SharedLibrary/Sources/Shared/Network/Archive.h index e7eb09d..023f185 100644 --- a/SharedLibrary/Sources/Shared/Network/Archive.h +++ b/SharedLibrary/Sources/Shared/Network/Archive.h @@ -76,8 +76,7 @@ class Archive : public ICopyable { reinterpret_cast(ser.get())->Serialize(*this); } - template<> - void serializeSimple(Archive &ser) { + void serializeSimple(Archive &ser) { auto lastSetMode = ser.GetMode(); if (mode == Mode::Output) { ser.SetMode(Mode::Input); From 6fa30d9df37a78f5061c8d35e7592406abf34d0f Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 16:23:50 +0300 Subject: [PATCH 7/8] refact(archive): expect correct mode for <> operators --- SharedLibrary/Sources/Shared/Network/Archive.h | 12 +++++++----- .../Sources/Shared/Network/ISerializable.cpp | 3 ++- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/SharedLibrary/Sources/Shared/Network/Archive.h b/SharedLibrary/Sources/Shared/Network/Archive.h index 023f185..49fb2b1 100644 --- a/SharedLibrary/Sources/Shared/Network/Archive.h +++ b/SharedLibrary/Sources/Shared/Network/Archive.h @@ -30,7 +30,9 @@ class Archive : public ICopyable { template Archive &operator&(T &ser) { if constexpr (std::is_base_of_v) { - sf::Int32 id; *this >> id; // we know type, so drop excess id + if (mode == Mode::Output) { + sf::Int32 id; *this >> id; // we know type, so drop excess id + } reinterpret_cast(ser).Serialize(*this); } else { serializeSimple(ser); @@ -41,14 +43,14 @@ class Archive : public ICopyable { template Archive &operator>>(T &ser) { - if (mode == Mode::Output) *this & ser; - return *this; + EXPECT(mode == Mode::Output); + return *this & ser; } template Archive &operator<<(const T &ser) { - if (mode == Mode::Input) *this & const_cast(ser); - return *this; + EXPECT(mode == Mode::Input); + return *this & const_cast(ser); } protected: diff --git a/SharedLibrary/Sources/Shared/Network/ISerializable.cpp b/SharedLibrary/Sources/Shared/Network/ISerializable.cpp index e7d4f83..fe90167 100644 --- a/SharedLibrary/Sources/Shared/Network/ISerializable.cpp +++ b/SharedLibrary/Sources/Shared/Network/ISerializable.cpp @@ -14,7 +14,8 @@ using namespace network::protocol; namespace uf { void ISerializable::Serialize(Archive &archive) { - archive << sf::Int32(SerID()); + if (archive.GetMode() == Archive::Mode::Input) + archive << sf::Int32(SerID()); } #define DECLARE_SER(name) \ From b57035396008a2d881fb81fa56caa5d843323235 Mon Sep 17 00:00:00 2001 From: Insineer Date: Tue, 8 Oct 2019 17:34:07 +0300 Subject: [PATCH 8/8] refact(syncable): clarify interface --- OSS13 Server/Sources/World/Objects/Object.cpp | 10 ++++---- OSS13 Server/Sources/World/Tile.cpp | 10 ++++---- OSS13 Server/Sources/World/World.cpp | 3 +-- .../Sources/Shared/Network/Syncable.cpp | 19 ++++++--------- .../Sources/Shared/Network/Syncable.h | 6 ++--- .../Tests/Sources/Syncable_Tests.cpp | 23 +++++++++++++++++-- 6 files changed, 44 insertions(+), 27 deletions(-) diff --git a/OSS13 Server/Sources/World/Objects/Object.cpp b/OSS13 Server/Sources/World/Objects/Object.cpp index c4e1bc5..e050066 100644 --- a/OSS13 Server/Sources/World/Objects/Object.cpp +++ b/OSS13 Server/Sources/World/Objects/Object.cpp @@ -144,9 +144,12 @@ void Object::AddObject(Object *obj) { if (obj->GetHolder()) { if (!obj->GetHolder()->RemoveObject(obj)) return; - } else if (obj->GetTile()) + } else if (obj->GetTile()) { obj->GetTile()->RemoveObject(obj); - obj->DropUpdateState(); + } else { + obj->ResetChanges(); + } + content.push_back(obj); obj->holder = this; @@ -161,10 +164,9 @@ bool Object::RemoveObject(Object *obj) { if (obj->IsChanged()) { auto fieldsDiff = std::make_shared(); fieldsDiff->objId = obj->ID(); - fieldsDiff->fieldsChanges = obj->GetChanges(); + fieldsDiff->fieldsChanges = obj->PopChanges(); GetTile()->AddDiff(std::move(fieldsDiff), obj); } - obj->DropUpdateState(); obj->setTile(nullptr); obj->holder = nullptr; diff --git a/OSS13 Server/Sources/World/Tile.cpp b/OSS13 Server/Sources/World/Tile.cpp index bc86e28..6c2a54c 100644 --- a/OSS13 Server/Sources/World/Tile.cpp +++ b/OSS13 Server/Sources/World/Tile.cpp @@ -93,10 +93,10 @@ bool Tile::RemoveObject(Object *obj) { if (obj->IsChanged()) { auto fieldsDiff = std::make_shared(); fieldsDiff->objId = obj->ID(); - fieldsDiff->fieldsChanges = obj->GetChanges(); + fieldsDiff->fieldsChanges = obj->PopChanges(); AddDiff(std::move(fieldsDiff), obj); } - obj->DropUpdateState(); + if (removeObject(obj)) { auto diff = std::make_shared(); diff->objId = obj->ID(); @@ -193,15 +193,17 @@ void Tile::PlaceTo(Object *obj) { if (obj->IsChanged()) { auto fieldsDiff = std::make_shared(); fieldsDiff->objId = obj->ID(); - fieldsDiff->fieldsChanges = obj->GetChanges(); + fieldsDiff->fieldsChanges = obj->PopChanges(); lastTile->AddDiff(std::move(fieldsDiff), obj); } auto relocateAwayDiff = std::make_shared(); relocateAwayDiff->objId = obj->ID(); relocateAwayDiff->newCoords = pos; lastTile->AddDiff(relocateAwayDiff, obj); + } else { + obj->ResetChanges(); } - obj->DropUpdateState(); + addObject(obj); auto relocateDiff = std::make_shared(); diff --git a/OSS13 Server/Sources/World/World.cpp b/OSS13 Server/Sources/World/World.cpp index ce643fb..deb03cc 100644 --- a/OSS13 Server/Sources/World/World.cpp +++ b/OSS13 Server/Sources/World/World.cpp @@ -58,9 +58,8 @@ void World::Update(std::chrono::microseconds timeElapsed) { if (object && object->GetTile() && object->IsChanged()) { auto diff = std::make_shared(); diff->objId = object->ID(); - diff->fieldsChanges = object->GetChanges(); + diff->fieldsChanges = object->PopChanges(); object->GetTile()->AddDiff(std::move(diff), object.get()); - object->DropUpdateState(); } } } diff --git a/SharedLibrary/Sources/Shared/Network/Syncable.cpp b/SharedLibrary/Sources/Shared/Network/Syncable.cpp index bf502e2..464ace7 100644 --- a/SharedLibrary/Sources/Shared/Network/Syncable.cpp +++ b/SharedLibrary/Sources/Shared/Network/Syncable.cpp @@ -9,7 +9,7 @@ void GeneralSyncField::setChanged() { changed = true; syncable->changed = true; } // namespace detail -SyncableChanges Syncable::GetChanges() { +SyncableChanges Syncable::PopChanges() { SyncableChanges changes; changes.archive.SetMode(Archive::Mode::Input); std::size_t changedCount = 0; @@ -17,15 +17,16 @@ SyncableChanges Syncable::GetChanges() { if (getField(i)->changed) changedCount++; } - EXPECT_WITH_MSG(changedCount, "Empty SyncableChanges are created!"); changes.archive << sf::Int32(changedCount); for (std::size_t i = 0; i < fieldsOffsets.size(); i++) { if (getField(i)->changed) { changes.archive << sf::Int32(i); getField(i)->Serialize(changes.archive); + getField(i)->changed = false; } } + changed = false; return changes; } @@ -33,27 +34,21 @@ void Syncable::AmendChanges(SyncableChanges &&changes) { changes.archive.SetMode(Archive::Mode::Output); sf::Int32 changedCount; changes.archive >> changedCount; - do { + while (changedCount--) { sf::Int32 fieldNumber; changes.archive >> fieldNumber; changes.archive >> *getField(std::size_t(fieldNumber)); - } while (--changedCount); + }; } -void Syncable::DropUpdateState() { +void Syncable::ResetChanges() { for (std::size_t i = 0; i < fieldsOffsets.size(); i++) getField(i)->changed = false; changed = false; } bool Syncable::IsChanged() { - bool t = false; - for (std::size_t i = 0; i < fieldsOffsets.size(); i++) { - if (getField(i)->changed) - t = true; - } - EXPECT(t || !changed); - return changed; + return changed; } void Syncable::Serialize(Archive &ar) { diff --git a/SharedLibrary/Sources/Shared/Network/Syncable.h b/SharedLibrary/Sources/Shared/Network/Syncable.h index e8c22ed..2886d7d 100644 --- a/SharedLibrary/Sources/Shared/Network/Syncable.h +++ b/SharedLibrary/Sources/Shared/Network/Syncable.h @@ -46,7 +46,7 @@ struct SyncField : public detail::GeneralSyncField { SyncField &operator=(const T &value) { this->value = value; setChanged(); return *this; } operator const T &() const { return value; } - T &GetValue() { return value; }; + const T &GetValue() { return value; }; void Serialize(Archive &ar) final { uf::ISerializable::Serialize(ar); @@ -74,10 +74,10 @@ DEFINE_SERIALIZABLE_END struct Syncable : public uf::ISerializable { friend detail::GeneralSyncField; - SyncableChanges GetChanges(); + SyncableChanges PopChanges(); void AmendChanges(SyncableChanges &&changes); + void ResetChanges(); - void DropUpdateState(); bool IsChanged(); void Serialize(Archive &ar) final; diff --git a/SharedLibrary/Tests/Sources/Syncable_Tests.cpp b/SharedLibrary/Tests/Sources/Syncable_Tests.cpp index cc78dc8..c03cfa9 100644 --- a/SharedLibrary/Tests/Sources/Syncable_Tests.cpp +++ b/SharedLibrary/Tests/Sources/Syncable_Tests.cpp @@ -12,12 +12,31 @@ DEFINE_SYNCABLE(TestSyncable) } DEFINE_SYNCABLE_END -TEST(Syncable, test) { +TEST(Syncable, IsChangedReturnsTrueAfterFieldChange) { + TestSyncable testSyncable; + testSyncable.a = 12345; + + CHECK(testSyncable.IsChanged()); +} + +TEST(Syncable, CorrectValuesAfterAmend) { TestSyncable testSyncable; testSyncable.a = 12345; testSyncable.b = "test string"; - auto changes = testSyncable.GetChanges(); + auto changes = testSyncable.PopChanges(); + + TestSyncable otherSyncable; + otherSyncable.AmendChanges(std::move(changes)); + + CHECK(testSyncable.a.GetValue() == otherSyncable.a.GetValue()); + CHECK(testSyncable.b.GetValue() == otherSyncable.b.GetValue()); +} + +TEST(Syncable, AmendDefaultValues) { + TestSyncable testSyncable; + + auto changes = testSyncable.PopChanges(); TestSyncable otherSyncable; otherSyncable.AmendChanges(std::move(changes));