Index: source/gui/scripting/ScriptFunctions.cpp =================================================================== --- source/gui/scripting/ScriptFunctions.cpp +++ source/gui/scripting/ScriptFunctions.cpp @@ -39,7 +39,6 @@ #include "lobby/IXmppClient.h" #include "maths/FixedVector3D.h" #include "network/NetClient.h" -#include "network/NetMessage.h" #include "network/NetServer.h" #include "network/StunClient.h" #include "ps/CConsole.h" Index: source/network/Fsm.h =================================================================== --- /dev/null +++ source/network/Fsm.h @@ -0,0 +1,167 @@ +/* Copyright (C) 2017 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#ifndef FSM_H +#define FSM_H + +#include "NetMessageBuffer.h" + +class CFsmEvent; +class CFsmTransition; +class CFsm; + +using Action = bool(*)(void* pContext, const CFsmEvent& pEvent); + +struct StoredAction +{ + Action m_Function; + void* m_Context; +}; + +/** + * Represents a signal in the state machine that a change has occurred. + * The CFsmEvent objects are under the control of CFsm so + * they are created and deleted via CFsm. + */ +class CFsmEvent +{ +public: + CFsmEvent(u32 type, const CNetMessageBuffer* buffer); + + u32 GetType() const + { + return m_Type; + } + + const CNetMessageBuffer& GetMessageBuffer() const + { + ENSURE(m_Buffer); + return *m_Buffer; + } + +private: + const CNetMessageBuffer* m_Buffer; + u32 m_Type; +}; + +/** + * An association of event, condition, action and next state. + */ +class CFsmTransition +{ +public: + CFsmTransition(u32 state, u32 eventType, u32 nextState, StoredAction action); + + u32 GetCurrState() const + { + return m_CurrState; + } + + u32 GetEventType() const + { + return m_EventType; + } + + u32 GetNextState() const + { + return m_NextState; + } + + bool RunAction(const CFsmEvent* event) const; + +private: + u32 m_CurrState; + u32 m_EventType; + u32 m_NextState; + StoredAction m_Action; +}; + +/** + * Manages states, events, actions and transitions + * between states. It provides an interface for advertising + * events and track the current state. The implementation is + * a Mealy state machine, so the system respond to events + * and execute some action. + * + * A Mealy state machine has behaviour associated with state + * transitions; Mealy machines are event driven where an + * event triggers a state transition + */ +class CFsm +{ +public: + CFsm(u32 firstState); + virtual ~CFsm() {} + + void AddTransition(u32 state, u32 eventType, u32 nextState); + void AddTransition(u32 state, u32 eventType, u32 nextState, Action action, void* context); + + void SetCurrState(u32 state) + { + m_CurrState = state; + } + + u32 GetCurrState() const + { + return m_CurrState; + } + + void SetNextState(u32 nextState) + { + m_NextState = nextState; + } + + bool Update(u32 type, const CNetMessageBuffer* message); + +private: + const u32 INVALID_STATE = ~0; + + using StateSet = std::set; + using EventSet = std::set; + using TransitionList = std::vector; + + const CFsmTransition* GetTransition(u32 state, u32 eventType) const; + + void AddState(u32 state) + { + m_States.insert(state); + } + + void AddEvent(u32 eventType) + { + m_Events.insert(eventType); + } + + bool IsValidState(u32 state) const + { + return m_States.find(state) != m_States.end(); + } + + bool IsValidEvent(u32 eventType) const + { + return m_Events.find(eventType) != m_Events.end(); + } + + u32 m_FirstState; + u32 m_CurrState; + u32 m_NextState; + StateSet m_States; + EventSet m_Events; + TransitionList m_Transitions; +}; + +#endif // FSM_H Index: source/network/Fsm.cpp =================================================================== --- /dev/null +++ source/network/Fsm.cpp @@ -0,0 +1,100 @@ +/* Copyright (C) 2017 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#include "precompiled.h" +#include "Fsm.h" + +CFsmEvent::CFsmEvent(u32 type, const CNetMessageBuffer* buffer) : + m_Buffer(buffer), + m_Type(type) +{ +} + +CFsmTransition::CFsmTransition(u32 state, u32 eventType, u32 nextState, StoredAction action) : + m_CurrState(state), + m_EventType(eventType), + m_NextState(nextState), + m_Action(action) +{ +} + +bool CFsmTransition::RunAction(const CFsmEvent* event) const +{ + if (m_Action.m_Function) + return m_Action.m_Function(m_Action.m_Context, *event); + return true; +} + +CFsm::CFsm(u32 firstState) : + m_FirstState(firstState), + m_CurrState(firstState), + m_NextState(INVALID_STATE) +{ +} + +void CFsm::AddTransition(u32 state, u32 eventType, u32 nextState) +{ + AddState(state); + AddEvent(eventType); + AddState(nextState); + + m_Transitions.emplace_back(state, eventType, nextState, StoredAction{nullptr, nullptr}); +} + +void CFsm::AddTransition(u32 state, u32 eventType, u32 nextState, Action action, void* context ) +{ + AddState(state); + AddEvent(eventType); + AddState(nextState); + + m_Transitions.emplace_back(state, eventType, nextState, StoredAction{action, context}); +} + +bool CFsm::Update(u32 type, const CNetMessageBuffer* message) +{ + const CFsmTransition* transition = GetTransition(m_CurrState, type); + if (!transition) + return false; + + // Save the default state transition (actions might call SetNextState to override this) + SetNextState(transition->GetNextState()); + + CFsmEvent event(type, message); + if (!transition->RunAction(&event)) + return false; + + m_CurrState = m_NextState; + + SetNextState(INVALID_STATE); + + return true; +} + +const CFsmTransition* CFsm::GetTransition(u32 state, u32 eventType) const +{ + if (!IsValidState(state) || !IsValidEvent(eventType)) + return nullptr; + + TransitionList::const_iterator it = std::find_if(m_Transitions.begin(), m_Transitions.end(), [state, eventType](const CFsmTransition& transition) { + return transition.GetCurrState() == state && transition.GetEventType() == eventType; + }); + + if (it == m_Transitions.end()) + return nullptr; + + return &(*it); +} Index: source/network/NMTCreator.h =================================================================== --- source/network/NMTCreator.h +++ /dev/null @@ -1,326 +0,0 @@ -/* Copyright (C) 2015 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#include "Serialization.h" -#include - -// If included from within the NMT Creation process, perform a pass -#ifdef CREATING_NMT - -#include NMT_CREATE_HEADER_NAME - -#undef START_NMTS -#undef END_NMTS -#undef START_NMT_CLASS -#undef START_NMT_CLASS_DERIVED -#undef NMT_FIELD_INT -#undef NMT_FIELD -#undef NMT_START_ARRAY -#undef NMT_END_ARRAY -#undef END_NMT_CLASS - -#else -// If not within the creation process, and called with argument, perform the -// creation process with the header specified -#ifdef NMT_CREATE_HEADER_NAME - -#ifndef ARRAY_STRUCT_PREFIX -#define ARRAY_STRUCT_PREFIX(_nm) S_##_nm -#endif - -#define CREATING_NMT - -#ifndef NMT_CREATOR_IMPLEMENT - -/*************************************************************************/ -// Pass 1, class definition -#define NMT_CREATOR_PASS_CLASSDEF -#define START_NMTS() -#define END_NMTS() - -#define START_NMT_CLASS(_nm, _tp) \ - START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp) - -/** - * Start the definition of a network message type. - * - * @param _base The name of the base class of the message - * @param _nm The name of the class - * @param _tp The NetMessageType associated with the class. It is *not* safe to - * have several classes with the same value of _tp in the same executable - */ -#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \ -CNetMessage *Deserialize##_nm(const u8 *, size_t); \ -class _nm: public _base \ -{ \ -protected: \ - _nm(NetMessageType type): _base(type) {}\ - \ - /* This one is for subclasses that want to use the base class' string */ \ - /* converters to get SubMessage { , ... } */ \ - CStr ToStringRaw() const;\ -public: \ - _nm(): _base(_tp) {} \ - virtual size_t GetSerializedLength() const; \ - virtual u8 *Serialize(u8 *buffer) const; \ - virtual const u8 *Deserialize(const u8 *pos, const u8 *end); \ - virtual CStr ToString() const; \ - inline operator CStr () const \ - { return ToString(); } - -/** - * Add an integer field to the message type. - * - * @param _nm The name of the field - * @param _hosttp The local type of the field (the data type used in the field - * definition) - * @param _netsz The number of bytes that should be serialized. If the variable - * has a value larger than the maximum value of the specified network size, - * higher order bytes will be discarded. - */ -#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \ - _hosttp _nm; - -/** - * Add a generic field to the message type. The data type must be a class - * implementing the ISerializable interface - * - * @param _tp The local data type of the field - * @param _nm The name of the field - * @see ISerializable - */ -#define NMT_FIELD(_tp, _nm) \ - _tp _nm; - -#define NMT_START_ARRAY(_nm) \ - struct ARRAY_STRUCT_PREFIX(_nm); \ - std::vector _nm; \ - struct ARRAY_STRUCT_PREFIX(_nm) { - -#define NMT_END_ARRAY() \ - }; - -#define END_NMT_CLASS() }; - -#include "NMTCreator.h" -#undef NMT_CREATOR_PASS_CLASSDEF - -#else // NMT_CREATOR_IMPLEMENT - -#include "StringConverters.h" - -/*************************************************************************/ -// Pass 2, GetSerializedLength -#define NMT_CREATOR_PASS_GETLENGTH -#define START_NMTS() -#define END_NMTS() - -#define START_NMT_CLASS(_nm, _tp) \ - START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp) -#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \ -size_t _nm::GetSerializedLength() const \ -{ \ - size_t ret=_base::GetSerializedLength(); \ - const _nm *thiz=this;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_START_ARRAY(_nm) \ - std::vector ::const_iterator it=_nm.begin(); \ - while (it != _nm.end()) \ - { \ - const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_END_ARRAY() \ - ++it; \ - } - -#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \ - ret += _netsz; - -#define NMT_FIELD(_tp, _nm) \ - ret += thiz->_nm.GetSerializedLength(); - -#define END_NMT_CLASS() \ - return ret; \ -}; - -#include "NMTCreator.h" -#undef NMT_CREATOR_PASS_GETLENGTH - -/*************************************************************************/ -// Pass 3, Serialize - -#define NMT_CREATOR_PASS_SERIALIZE - -#define START_NMTS() -#define END_NMTS() - -#define START_NMT_CLASS(_nm, _tp) \ - START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp) -#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \ -u8 *_nm::Serialize(u8 *buffer) const \ -{ \ - /*printf("In " #_nm "::Serialize()\n");*/ \ - u8 *pos=_base::Serialize(buffer); \ - const _nm *thiz=this;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_START_ARRAY(_nm) \ - std::vector ::const_iterator it=_nm.begin(); \ - while (it != _nm.end()) \ - { \ - const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_END_ARRAY() \ - ++it; \ - } - -#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \ - Serialize_int_##_netsz(pos, thiz->_nm); \ - -#define NMT_FIELD(_tp, _nm) \ - pos=thiz->_nm.Serialize(pos); - -#define END_NMT_CLASS() \ - return pos; \ -} - -#include "NMTCreator.h" - -#undef NMT_CREATOR_PASS_SERIALIZE - -/*************************************************************************/ -// Pass 4, Deserialize - -#define NMT_CREATOR_PASS_DESERIALIZE - -#define START_NMTS() -#define END_NMTS() - -#define BAIL_DESERIALIZER return NULL - -#define START_NMT_CLASS(_nm, _tp) \ - START_NMT_CLASS_DERIVED(CNetMessage, _nm, _tp) -#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \ -const u8 *_nm::Deserialize(const u8 *pos, const u8 *end) \ -{ \ - pos=_base::Deserialize(pos, end); \ - _nm *thiz=this; \ - /*printf("In Deserialize" #_nm "\n"); */\ - UNUSED2(thiz); // preempt any "unused" warning - - -#define NMT_START_ARRAY(_nm) \ - while (pos < end) \ - { \ - ARRAY_STRUCT_PREFIX(_nm) *thiz=&*_nm.insert(_nm.end(), ARRAY_STRUCT_PREFIX(_nm)());\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_END_ARRAY() \ - } - -#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \ - if (pos+_netsz > end) BAIL_DESERIALIZER; \ - Deserialize_int_##_netsz(pos, thiz->_nm); \ - /*printf("\t" #_nm " == 0x%x\n", thiz->_nm);*/ - -#define NMT_FIELD(_tp, _nm) \ - if ((pos=thiz->_nm.Deserialize(pos, end)) == NULL) BAIL_DESERIALIZER; - -#define END_NMT_CLASS() \ - return pos; \ -} - -#include "NMTCreator.h" - -#undef BAIL_DESERIALIZER - -#undef NMT_CREATOR_PASS_DESERIALIZE - -/*************************************************************************/ -// Pass 5, String Representation - -#define START_NMTS() -#define END_NMTS() - -#define START_NMT_CLASS(_nm, _tp) \ -CStr _nm::ToString() const \ -{ \ - CStr ret=#_nm " { "; \ - return ret + ToStringRaw() + " }"; \ -} \ -CStr _nm::ToStringRaw() const \ -{ \ - CStr ret; \ - const _nm *thiz=this;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define START_NMT_CLASS_DERIVED(_base, _nm, _tp) \ -CStr _nm::ToString() const \ -{ \ - CStr ret=#_nm " { "; \ - return ret + ToStringRaw() + " }"; \ -} \ -CStr _nm::ToStringRaw() const \ -{ \ - CStr ret=_base::ToStringRaw() + ", "; \ - const _nm *thiz=this;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_START_ARRAY(_nm) \ - ret+=#_nm ": { "; \ - std::vector < ARRAY_STRUCT_PREFIX(_nm) >::const_iterator it=_nm.begin(); \ - while (it != _nm.end()) \ - { \ - ret+=" { "; \ - const ARRAY_STRUCT_PREFIX(_nm) *thiz=&*it;\ - UNUSED2(thiz); // preempt any "unused" warning - -#define NMT_END_ARRAY() \ - ++it; \ - ret=ret.substr(0, ret.length()-2)+" }, "; \ - } \ - ret=ret.substr(0, ret.length()-2)+" }, "; - -#define NMT_FIELD_INT(_nm, _hosttp, _netsz) \ - ret += #_nm ": "; \ - ret += NetMessageStringConvert(thiz->_nm); \ - ret += ", "; - -#define NMT_FIELD(_tp, _nm) \ - ret += #_nm ": "; \ - ret += NetMessageStringConvert(thiz->_nm); \ - ret += ", "; - -#define END_NMT_CLASS() \ - return ret.substr(0, ret.length()-2); \ -} - -#include "NMTCreator.h" - -#endif // #ifdef NMT_CREATOR_IMPLEMENT - -/*************************************************************************/ -// Cleanup -#undef NMT_CREATE_HEADER_NAME -#undef NMT_CREATOR_IMPLEMENT -#undef CREATING_NMT - -#endif // #ifdef NMT_CREATE_HEADER_NAME -#endif // #ifndef CREATING_NMT Index: source/network/NetClient.h =================================================================== --- source/network/NetClient.h +++ source/network/NetClient.h @@ -18,7 +18,7 @@ #ifndef NETCLIENT_H #define NETCLIENT_H -#include "network/fsm.h" +#include "network/Fsm.h" #include "network/NetFileTransfer.h" #include "network/NetHost.h" #include "scriptinterface/ScriptVal.h" @@ -166,7 +166,7 @@ * @param message message to send * @return true on success */ - bool SendMessage(const CNetMessage* message); + bool SendMessage(const CNetMessageBuffer& message); /** * Call when the network connection has been successfully initiated. @@ -181,7 +181,7 @@ /** * Call when a message has been received from the network. */ - bool HandleMessage(CNetMessage* message); + bool HandleMessage(const CNetMessageBuffer& message); /** * Call when the game has started and all data files have been loaded, @@ -219,25 +219,25 @@ private: // Net message / FSM transition handlers - static bool OnConnect(void* context, CFsmEvent* event); - static bool OnHandshake(void* context, CFsmEvent* event); - static bool OnHandshakeResponse(void* context, CFsmEvent* event); - static bool OnAuthenticate(void* context, CFsmEvent* event); - static bool OnChat(void* context, CFsmEvent* event); - static bool OnReady(void* context, CFsmEvent* event); - static bool OnGameSetup(void* context, CFsmEvent* event); - static bool OnPlayerAssignment(void* context, CFsmEvent* event); - static bool OnInGame(void* context, CFsmEvent* event); - static bool OnGameStart(void* context, CFsmEvent* event); - static bool OnJoinSyncStart(void* context, CFsmEvent* event); - static bool OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event); - static bool OnRejoined(void* context, CFsmEvent* event); - static bool OnKicked(void* context, CFsmEvent* event); - static bool OnClientTimeout(void* context, CFsmEvent* event); - static bool OnClientPerformance(void* context, CFsmEvent* event); - static bool OnClientsLoading(void* context, CFsmEvent* event); - static bool OnClientPaused(void* context, CFsmEvent* event); - static bool OnLoadedGame(void* context, CFsmEvent* event); + static bool OnConnect(void* context, const CFsmEvent& event); + static bool OnHandshake(void* context, const CFsmEvent& event); + static bool OnHandshakeResponse(void* context, const CFsmEvent& event); + static bool OnAuthenticate(void* context, const CFsmEvent& event); + static bool OnChat(void* context, const CFsmEvent& event); + static bool OnReady(void* context, const CFsmEvent& event); + static bool OnGameSetup(void* context, const CFsmEvent& event); + static bool OnPlayerAssignment(void* context, const CFsmEvent& event); + static bool OnInGame(void* context, const CFsmEvent& event); + static bool OnGameStart(void* context, const CFsmEvent& event); + static bool OnJoinSyncStart(void* context, const CFsmEvent& event); + static bool OnJoinSyncEndCommandBatch(void* context, const CFsmEvent& event); + static bool OnRejoined(void* context, const CFsmEvent& event); + static bool OnKicked(void* context, const CFsmEvent& event); + static bool OnClientTimeout(void* context, const CFsmEvent& event); + static bool OnClientPerformance(void* context, const CFsmEvent& event); + static bool OnClientsLoading(void* context, const CFsmEvent& event); + static bool OnClientPaused(void* context, const CFsmEvent& event); + static bool OnLoadedGame(void* context, const CFsmEvent& event); /** * Take ownership of a session object, and use it for all network communication. Index: source/network/NetClient.cpp =================================================================== --- source/network/NetClient.cpp +++ source/network/NetClient.cpp @@ -20,7 +20,6 @@ #include "NetClient.h" #include "NetClientTurnManager.h" -#include "NetMessage.h" #include "NetSession.h" #include "lib/byte_order.h" @@ -36,7 +35,7 @@ #include "scriptinterface/ScriptInterface.h" #include "simulation2/Simulation2.h" -CNetClient *g_NetClient = NULL; +CNetClient* g_NetClient = nullptr; /** * Async task for receiving the initial game state when rejoining an @@ -60,7 +59,7 @@ // Pretend the server told us to start the game CGameStartMessage start; - m_Client.HandleMessage(&start); + m_Client.HandleMessage(start); } private: @@ -68,76 +67,77 @@ }; CNetClient::CNetClient(CGame* game, bool isLocalClient) : - m_Session(NULL), + CFsm(NCS_UNCONNECTED), + m_Game(game), m_UserName(L"anonymous"), - m_GUID(ps_generate_guid()), m_HostID((u32)-1), m_ClientTurnManager(NULL), m_Game(game), - m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetContext()), + m_Session(nullptr), + m_ClientTurnManager(nullptr), + m_HostID((u32)-1), + m_Rejoin(false), m_IsLocalClient(isLocalClient), - m_LastConnectionCheck(0), - m_Rejoin(false) + m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetContext()), + m_GUID(ps_generate_guid()), + m_LastConnectionCheck(0) { - m_Game->SetTurnManager(NULL); // delete the old local turn manager so we don't accidentally use it + m_Game->SetTurnManager(nullptr); // delete the old local turn manager so we don't accidentally use it void* context = this; JS_AddExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this); // Set up transitions for session - AddTransition(NCS_UNCONNECTED, (uint)NMT_CONNECT_COMPLETE, NCS_CONNECT, (void*)&OnConnect, context); - - AddTransition(NCS_CONNECT, (uint)NMT_SERVER_HANDSHAKE, NCS_HANDSHAKE, (void*)&OnHandshake, context); - - AddTransition(NCS_HANDSHAKE, (uint)NMT_SERVER_HANDSHAKE_RESPONSE, NCS_AUTHENTICATE, (void*)&OnHandshakeResponse, context); - - AddTransition(NCS_AUTHENTICATE, (uint)NMT_AUTHENTICATE_RESULT, NCS_INITIAL_GAMESETUP, (void*)&OnAuthenticate, context); - - AddTransition(NCS_INITIAL_GAMESETUP, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context); - - AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context); - AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context); - AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context); - AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context); - AddTransition(NCS_PREGAME, (uint)NMT_KICKED, NCS_PREGAME, (void*)&OnKicked, context); - AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_PREGAME, (void*)&OnClientTimeout, context); - AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_PREGAME, (void*)&OnClientPerformance, context); - AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context); - AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, (void*)&OnJoinSyncStart, context); - - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, (void*)&OnGameSetup, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_JOIN_SYNCING, (void*)&OnPlayerAssignment, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_KICKED, NCS_JOIN_SYNCING, (void*)&OnKicked, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_TIMEOUT, NCS_JOIN_SYNCING, (void*)&OnClientTimeout, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_PERFORMANCE, NCS_JOIN_SYNCING, (void*)&OnClientPerformance, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_START, NCS_JOIN_SYNCING, (void*)&OnGameStart, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_SIMULATION_COMMAND, NCS_JOIN_SYNCING, (void*)&OnInGame, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_END_COMMAND_BATCH, NCS_JOIN_SYNCING, (void*)&OnJoinSyncEndCommandBatch, context); - AddTransition(NCS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context); - - AddTransition(NCS_LOADING, (uint)NMT_CHAT, NCS_LOADING, (void*)&OnChat, context); - AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, (void*)&OnGameSetup, context); - AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, (void*)&OnPlayerAssignment, context); - AddTransition(NCS_LOADING, (uint)NMT_KICKED, NCS_LOADING, (void*)&OnKicked, context); - AddTransition(NCS_LOADING, (uint)NMT_CLIENT_TIMEOUT, NCS_LOADING, (void*)&OnClientTimeout, context); - AddTransition(NCS_LOADING, (uint)NMT_CLIENT_PERFORMANCE, NCS_LOADING, (void*)&OnClientPerformance, context); - AddTransition(NCS_LOADING, (uint)NMT_CLIENTS_LOADING, NCS_LOADING, (void*)&OnClientsLoading, context); - AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context); - - AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context); - AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context); - AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, (void*)&OnClientTimeout, context); - AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, (void*)&OnClientPerformance, context); - AddTransition(NCS_INGAME, (uint)NMT_CLIENTS_LOADING, NCS_INGAME, (void*)&OnClientsLoading, context); - AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PAUSED, NCS_INGAME, (void*)&OnClientPaused, context); - AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context); - AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context); - AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context); - AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, context); - AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, (void*)&OnInGame, context); - AddTransition(NCS_INGAME, (uint)NMT_END_COMMAND_BATCH, NCS_INGAME, (void*)&OnInGame, context); - - // Set first state - SetFirstState(NCS_UNCONNECTED); + AddTransition(NCS_UNCONNECTED, (uint)NMT_CONNECT_COMPLETE, NCS_CONNECT, &OnConnect, context); + + AddTransition(NCS_CONNECT, (uint)NMT_SERVER_HANDSHAKE, NCS_HANDSHAKE, &OnHandshake, context); + + AddTransition(NCS_HANDSHAKE, (uint)NMT_SERVER_HANDSHAKE_RESPONSE, NCS_AUTHENTICATE, &OnHandshakeResponse, context); + + AddTransition(NCS_AUTHENTICATE, (uint)NMT_AUTHENTICATE_RESULT, NCS_INITIAL_GAMESETUP, &OnAuthenticate, context); + + AddTransition(NCS_INITIAL_GAMESETUP, (uint)NMT_GAME_SETUP, NCS_PREGAME, &OnGameSetup, context); + + AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, &OnChat, context); + AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, &OnReady, context); + AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, &OnGameSetup, context); + AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, &OnPlayerAssignment, context); + AddTransition(NCS_PREGAME, (uint)NMT_KICKED, NCS_PREGAME, &OnKicked, context); + AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_PREGAME, &OnClientTimeout, context); + AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_PREGAME, &OnClientPerformance, context); + AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, &OnGameStart, context); + AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, &OnJoinSyncStart, context); + + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, &OnChat, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, &OnGameSetup, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_JOIN_SYNCING, &OnPlayerAssignment, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_KICKED, NCS_JOIN_SYNCING, &OnKicked, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_TIMEOUT, NCS_JOIN_SYNCING, &OnClientTimeout, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_PERFORMANCE, NCS_JOIN_SYNCING, &OnClientPerformance, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_START, NCS_JOIN_SYNCING, &OnGameStart, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_SIMULATION_COMMAND, NCS_JOIN_SYNCING, &OnInGame, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_END_COMMAND_BATCH, NCS_JOIN_SYNCING, &OnJoinSyncEndCommandBatch, context); + AddTransition(NCS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NCS_INGAME, &OnLoadedGame, context); + + AddTransition(NCS_LOADING, (uint)NMT_CHAT, NCS_LOADING, &OnChat, context); + AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, &OnGameSetup, context); + AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, &OnPlayerAssignment, context); + AddTransition(NCS_LOADING, (uint)NMT_KICKED, NCS_LOADING, &OnKicked, context); + AddTransition(NCS_LOADING, (uint)NMT_CLIENT_TIMEOUT, NCS_LOADING, &OnClientTimeout, context); + AddTransition(NCS_LOADING, (uint)NMT_CLIENT_PERFORMANCE, NCS_LOADING, &OnClientPerformance, context); + AddTransition(NCS_LOADING, (uint)NMT_CLIENTS_LOADING, NCS_LOADING, &OnClientsLoading, context); + AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, &OnLoadedGame, context); + + AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, &OnRejoined, context); + AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, &OnKicked, context); + AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, &OnClientTimeout, context); + AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, &OnClientPerformance, context); + AddTransition(NCS_INGAME, (uint)NMT_CLIENTS_LOADING, NCS_INGAME, &OnClientsLoading, context); + AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PAUSED, NCS_INGAME, &OnClientPaused, context); + AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, &OnChat, context); + AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, &OnGameSetup, context); + AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, &OnPlayerAssignment, context); + AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, &OnInGame, context); + AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, &OnInGame, context); + AddTransition(NCS_INGAME, (uint)NMT_END_COMMAND_BATCH, NCS_INGAME, &OnInGame, context); } CNetClient::~CNetClient() @@ -299,7 +299,7 @@ PushGuiMessage(msg); } -bool CNetClient::SendMessage(const CNetMessage* message) +bool CNetClient::SendMessage(const CNetMessageBuffer& message) { if (!m_Session) return false; @@ -309,7 +309,7 @@ void CNetClient::HandleConnect() { - Update((uint)NMT_CONNECT_COMPLETE, NULL); + Update(NMT_CONNECT_COMPLETE, nullptr); } void CNetClient::HandleDisconnect(u32 reason) @@ -331,9 +331,8 @@ void CNetClient::SendGameSetupMessage(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface) { - CGameSetupMessage gameSetup(scriptInterface); - gameSetup.m_Data = attrs; - SendMessage(&gameSetup); + CGameSetupMessage gameSetup(scriptInterface, (JS::HandleValue)attrs); + SendMessage(gameSetup); } void CNetClient::SendAssignPlayerMessage(const int playerID, const CStr& guid) @@ -341,39 +340,39 @@ CAssignPlayerMessage assignPlayer; assignPlayer.m_PlayerID = playerID; assignPlayer.m_GUID = guid; - SendMessage(&assignPlayer); + SendMessage(assignPlayer); } void CNetClient::SendChatMessage(const std::wstring& text) { CChatMessage chat; chat.m_Message = text; - SendMessage(&chat); + SendMessage(chat); } void CNetClient::SendReadyMessage(const int status) { CReadyMessage readyStatus; readyStatus.m_Status = status; - SendMessage(&readyStatus); + SendMessage(readyStatus); } void CNetClient::SendClearAllReadyMessage() { CClearAllReadyMessage clearAllReady; - SendMessage(&clearAllReady); + SendMessage(clearAllReady); } void CNetClient::SendStartGameMessage() { CGameStartMessage gameStart; - SendMessage(&gameStart); + SendMessage(gameStart); } void CNetClient::SendRejoinedMessage() { CRejoinedMessage rejoinedMessage; - SendMessage(&rejoinedMessage); + SendMessage(rejoinedMessage); } void CNetClient::SendKickPlayerMessage(const CStrW& playerName, bool ban) @@ -381,17 +380,17 @@ CKickedMessage kickPlayer; kickPlayer.m_Name = playerName; kickPlayer.m_Ban = ban; - SendMessage(&kickPlayer); + SendMessage(kickPlayer); } void CNetClient::SendPausedMessage(bool pause) { CClientPausedMessage pausedMessage; pausedMessage.m_Pause = pause; - SendMessage(&pausedMessage); + SendMessage(pausedMessage); } -bool CNetClient::HandleMessage(CNetMessage* message) +bool CNetClient::HandleMessage(const CNetMessageBuffer& message) { // Handle non-FSM messages first @@ -401,9 +400,9 @@ if (status != INFO::SKIPPED) return false; - if (message->GetType() == NMT_FILE_TRANSFER_REQUEST) + if (message.GetType() == NMT_FILE_TRANSFER_REQUEST) { - CFileTransferRequestMessage* reqMessage = (CFileTransferRequestMessage*)message; + CFileTransferRequestMessage reqMessage(message); // TODO: we should support different transfer request types, instead of assuming // it's always requesting the simulation state @@ -422,15 +421,15 @@ std::string compressed; CompressZLib(stream.str(), compressed, true); - m_Session->GetFileTransferer().StartResponse(reqMessage->m_RequestID, compressed); + m_Session->GetFileTransferer().StartResponse(reqMessage.m_RequestID, compressed); return true; } // Update FSM - bool ok = Update(message->GetType(), message); + bool ok = Update(message.GetType(), &message); if (!ok) - LOGERROR("Net client: Error running FSM update (type=%d state=%d)", (int)message->GetType(), (int)GetCurrState()); + LOGERROR("Net client: Error running FSM update (type=%d state=%d)", (int)message.GetType(), (int)GetCurrState()); return ok; } @@ -474,12 +473,12 @@ CLoadedGameMessage loaded; loaded.m_CurrentTurn = m_ClientTurnManager->GetCurrentTurn(); - SendMessage(&loaded); + SendMessage(loaded); } -bool CNetClient::OnConnect(void* context, CFsmEvent* event) +bool CNetClient::OnConnect(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CONNECT_COMPLETE); + ENSURE(event.GetType() == (uint)NMT_CONNECT_COMPLETE); CNetClient* client = (CNetClient*)context; @@ -493,9 +492,9 @@ return true; } -bool CNetClient::OnHandshake(void* context, CFsmEvent* event) +bool CNetClient::OnHandshake(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_SERVER_HANDSHAKE); + ENSURE(event.GetType() == (uint)NMT_SERVER_HANDSHAKE); CNetClient* client = (CNetClient*)context; @@ -503,14 +502,14 @@ handshake.m_MagicResponse = PS_PROTOCOL_MAGIC_RESPONSE; handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION; handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION; - client->SendMessage(&handshake); + client->SendMessage(handshake); return true; } -bool CNetClient::OnHandshakeResponse(void* context, CFsmEvent* event) +bool CNetClient::OnHandshakeResponse(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_SERVER_HANDSHAKE_RESPONSE); + ENSURE(event.GetType() == (uint)NMT_SERVER_HANDSHAKE_RESPONSE); CNetClient* client = (CNetClient*)context; @@ -519,26 +518,26 @@ authenticate.m_Name = client->m_UserName; authenticate.m_Password = L""; // TODO authenticate.m_IsLocalClient = client->m_IsLocalClient; - client->SendMessage(&authenticate); + client->SendMessage(authenticate); return true; } -bool CNetClient::OnAuthenticate(void* context, CFsmEvent* event) +bool CNetClient::OnAuthenticate(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_AUTHENTICATE_RESULT); + ENSURE(event.GetType() == (uint)NMT_AUTHENTICATE_RESULT); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CAuthenticateResultMessage* message = (CAuthenticateResultMessage*)event->GetParamRef(); + CAuthenticateResultMessage message(event.GetMessageBuffer()); - LOGMESSAGE("Net: Authentication result: host=%u, %s", message->m_HostID, utf8_from_wstring(message->m_Message)); + LOGMESSAGE("Net: Authentication result: host=%u, %s", message.m_HostID, utf8_from_wstring(message.m_Message)); - client->m_HostID = message->m_HostID; - client->m_Rejoin = message->m_Code == ARC_OK_REJOINING; + client->m_HostID = message.m_HostID; + client->m_Rejoin = message.m_Code == ARC_OK_REJOINING; JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'netstatus','status':'authenticated'})", &msg); @@ -548,82 +547,81 @@ return true; } -bool CNetClient::OnChat(void* context, CFsmEvent* event) +bool CNetClient::OnChat(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CHAT); + ENSURE(event.GetType() == (uint)NMT_CHAT); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CChatMessage* message = (CChatMessage*)event->GetParamRef(); + CChatMessage message(event.GetMessageBuffer()); JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'chat'})", &msg); - client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false); - client->GetScriptInterface().SetProperty(msg, "text", std::wstring(message->m_Message), false); + client->GetScriptInterface().SetProperty(msg, "guid", std::string(message.m_GUID), false); + client->GetScriptInterface().SetProperty(msg, "text", std::wstring(message.m_Message), false); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnReady(void* context, CFsmEvent* event) +bool CNetClient::OnReady(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_READY); + ENSURE(event.GetType() == (uint)NMT_READY); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CReadyMessage* message = (CReadyMessage*)event->GetParamRef(); + CReadyMessage message(event.GetMessageBuffer()); JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'ready'})", &msg); - client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false); - client->GetScriptInterface().SetProperty(msg, "status", int (message->m_Status), false); + client->GetScriptInterface().SetProperty(msg, "guid", std::string(message.m_GUID), false); + client->GetScriptInterface().SetProperty(msg, "status", int (message.m_Status), false); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnGameSetup(void* context, CFsmEvent* event) +bool CNetClient::OnGameSetup(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_GAME_SETUP); + ENSURE(event.GetType() == (uint)NMT_GAME_SETUP); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CGameSetupMessage* message = (CGameSetupMessage*)event->GetParamRef(); - - client->m_GameAttributes = message->m_Data; + CGameSetupMessage message(client->GetScriptInterface(), event.GetMessageBuffer()); + client->m_GameAttributes = message.m_JSData.m_Data; JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'gamesetup'})", &msg); - client->GetScriptInterface().SetProperty(msg, "data", message->m_Data, false); + client->GetScriptInterface().SetProperty(msg, "data", message.m_JSData.m_Data, false); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnPlayerAssignment(void* context, CFsmEvent* event) +bool CNetClient::OnPlayerAssignment(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_PLAYER_ASSIGNMENT); + ENSURE(event.GetType() == (uint)NMT_PLAYER_ASSIGNMENT); CNetClient* client = (CNetClient*)context; - CPlayerAssignmentMessage* message = (CPlayerAssignmentMessage*)event->GetParamRef(); + CPlayerAssignmentMessage message(event.GetMessageBuffer()); // Unpack the message PlayerAssignmentMap newPlayerAssignments; - for (size_t i = 0; i < message->m_Hosts.size(); ++i) + for (size_t i = 0; i < message.m_Hosts.size(); ++i) { PlayerAssignment assignment; assignment.m_Enabled = true; - assignment.m_Name = message->m_Hosts[i].m_Name; - assignment.m_PlayerID = message->m_Hosts[i].m_PlayerID; - assignment.m_Status = message->m_Hosts[i].m_Status; - newPlayerAssignments[message->m_Hosts[i].m_GUID] = assignment; + assignment.m_Name = message.m_Hosts[i].m_Name; + assignment.m_PlayerID = message.m_Hosts[i].m_PlayerID; + assignment.m_Status = message.m_Hosts[i].m_Status; + newPlayerAssignments[message.m_Hosts[i].m_GUID] = assignment; } client->m_PlayerAssignments.swap(newPlayerAssignments); @@ -633,9 +631,9 @@ return true; } -bool CNetClient::OnGameStart(void* context, CFsmEvent* event) +bool CNetClient::OnGameStart(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_GAME_START); + ENSURE(event.GetType() == (uint)NMT_GAME_START); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); @@ -659,9 +657,9 @@ return true; } -bool CNetClient::OnJoinSyncStart(void* context, CFsmEvent* event) +bool CNetClient::OnJoinSyncStart(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_JOIN_SYNC_START); + ENSURE(event.GetType() == (uint)NMT_JOIN_SYNC_START); CNetClient* client = (CNetClient*)context; @@ -673,15 +671,15 @@ return true; } -bool CNetClient::OnJoinSyncEndCommandBatch(void* context, CFsmEvent* event) +bool CNetClient::OnJoinSyncEndCommandBatch(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_END_COMMAND_BATCH); + ENSURE(event.GetType() == (uint)NMT_END_COMMAND_BATCH); CNetClient* client = (CNetClient*)context; - CEndCommandBatchMessage* endMessage = (CEndCommandBatchMessage*)event->GetParamRef(); + CEndCommandBatchMessage endMessage(event.GetMessageBuffer()); - client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength); + client->m_ClientTurnManager->FinishedAllCommands(endMessage.m_Turn, endMessage.m_TurnLength); // Execute all the received commands for the latest turn client->m_ClientTurnManager->UpdateFastForward(); @@ -689,48 +687,48 @@ return true; } -bool CNetClient::OnRejoined(void* context, CFsmEvent* event) +bool CNetClient::OnRejoined(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_REJOINED); + ENSURE(event.GetType() == (uint)NMT_REJOINED); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CRejoinedMessage* message = (CRejoinedMessage*)event->GetParamRef(); + CRejoinedMessage message(event.GetMessageBuffer()); JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({'type':'rejoined'})", &msg); - client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID), false); + client->GetScriptInterface().SetProperty(msg, "guid", std::string(message.m_GUID), false); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnKicked(void *context, CFsmEvent* event) +bool CNetClient::OnKicked(void *context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_KICKED); + ENSURE(event.GetType() == (uint)NMT_KICKED); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CKickedMessage* message = (CKickedMessage*)event->GetParamRef(); + CKickedMessage message(event.GetMessageBuffer()); JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({})", &msg); - client->GetScriptInterface().SetProperty(msg, "username", message->m_Name); + client->GetScriptInterface().SetProperty(msg, "username", message.m_Name); client->GetScriptInterface().SetProperty(msg, "type", CStr("kicked")); - client->GetScriptInterface().SetProperty(msg, "banned", message->m_Ban != 0); + client->GetScriptInterface().SetProperty(msg, "banned", message.m_Ban != 0); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnClientTimeout(void *context, CFsmEvent* event) +bool CNetClient::OnClientTimeout(void *context, const CFsmEvent& event) { // Report the timeout of some other client - ENSURE(event->GetType() == (uint)NMT_CLIENT_TIMEOUT); + ENSURE(event.GetType() == (uint)NMT_CLIENT_TIMEOUT); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); @@ -739,22 +737,22 @@ if (client->GetCurrState() == NCS_LOADING) return true; - CClientTimeoutMessage* message = (CClientTimeoutMessage*)event->GetParamRef(); + CClientTimeoutMessage message(event.GetMessageBuffer()); JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'client-timeout' })", &msg); - client->GetScriptInterface().SetProperty(msg, "guid", std::string(message->m_GUID)); - client->GetScriptInterface().SetProperty(msg, "lastReceivedTime", message->m_LastReceivedTime); + client->GetScriptInterface().SetProperty(msg, "guid", std::string(message.m_GUID)); + client->GetScriptInterface().SetProperty(msg, "lastReceivedTime", message.m_LastReceivedTime); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnClientPerformance(void *context, CFsmEvent* event) +bool CNetClient::OnClientPerformance(void *context, const CFsmEvent& event) { // Performance statistics for one or multiple clients - ENSURE(event->GetType() == (uint)NMT_CLIENT_PERFORMANCE); + ENSURE(event.GetType() == (uint)NMT_CLIENT_PERFORMANCE); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); @@ -763,33 +761,33 @@ if (client->GetCurrState() == NCS_LOADING) return true; - CClientPerformanceMessage* message = (CClientPerformanceMessage*)event->GetParamRef(); + CClientPerformanceMessage message(event.GetMessageBuffer()); // Display warnings for other clients with bad ping - for (size_t i = 0; i < message->m_Clients.size(); ++i) + for (size_t i = 0; i < message.m_Clients.size(); ++i) { - if (message->m_Clients[i].m_MeanRTT < DEFAULT_TURN_LENGTH_MP || message->m_Clients[i].m_GUID == client->m_GUID) + if (message.m_Clients[i].m_MeanRTT < DEFAULT_TURN_LENGTH_MP || message.m_Clients[i].m_GUID == client->m_GUID) continue; JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'client-latency' })", &msg); - client->GetScriptInterface().SetProperty(msg, "guid", message->m_Clients[i].m_GUID); - client->GetScriptInterface().SetProperty(msg, "meanRTT", message->m_Clients[i].m_MeanRTT); + client->GetScriptInterface().SetProperty(msg, "guid", message.m_Clients[i].m_GUID); + client->GetScriptInterface().SetProperty(msg, "meanRTT", message.m_Clients[i].m_MeanRTT); client->PushGuiMessage(msg); } return true; } -bool CNetClient::OnClientsLoading(void *context, CFsmEvent *event) +bool CNetClient::OnClientsLoading(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CLIENTS_LOADING); + ENSURE(event.GetType() == (uint)NMT_CLIENTS_LOADING); - CClientsLoadingMessage* message = (CClientsLoadingMessage*)event->GetParamRef(); + CClientsLoadingMessage message(event.GetMessageBuffer()); std::vector guids; - guids.reserve(message->m_Clients.size()); - for (const CClientsLoadingMessage::S_m_Clients& client : message->m_Clients) + guids.reserve(message.m_Clients.size()); + for (const CClientsLoadingMessage::SClient& client : message.m_Clients) guids.push_back(client.m_GUID); CNetClient* client = (CNetClient*)context; @@ -803,28 +801,28 @@ return true; } -bool CNetClient::OnClientPaused(void *context, CFsmEvent *event) +bool CNetClient::OnClientPaused(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED); + ENSURE(event.GetType() == (uint)NMT_CLIENT_PAUSED); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); JSAutoRequest rq(cx); - CClientPausedMessage* message = (CClientPausedMessage*)event->GetParamRef(); + CClientPausedMessage message(event.GetMessageBuffer()); JS::RootedValue msg(cx); client->GetScriptInterface().Eval("({ 'type':'paused' })", &msg); - client->GetScriptInterface().SetProperty(msg, "pause", message->m_Pause != 0); - client->GetScriptInterface().SetProperty(msg, "guid", message->m_GUID); + client->GetScriptInterface().SetProperty(msg, "pause", message.m_Pause != 0); + client->GetScriptInterface().SetProperty(msg, "guid", message.m_GUID); client->PushGuiMessage(msg); return true; } -bool CNetClient::OnLoadedGame(void* context, CFsmEvent* event) +bool CNetClient::OnLoadedGame(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); + ENSURE(event.GetType() == (uint)NMT_LOADED_GAME); CNetClient* client = (CNetClient*)context; JSContext* cx = client->GetScriptInterface().GetContext(); @@ -845,30 +843,33 @@ return true; } -bool CNetClient::OnInGame(void *context, CFsmEvent* event) +bool CNetClient::OnInGame(void *context, const CFsmEvent& event) { // TODO: should split each of these cases into a separate method CNetClient* client = (CNetClient*)context; - CNetMessage* message = (CNetMessage*)event->GetParamRef(); - if (message) + const CNetMessageBuffer& message = event.GetMessageBuffer(); + switch (message.GetType()) { - if (message->GetType() == NMT_SIMULATION_COMMAND) - { - CSimulationMessage* simMessage = static_cast (message); - client->m_ClientTurnManager->OnSimulationMessage(simMessage); - } - else if (message->GetType() == NMT_SYNC_ERROR) - { - CSyncErrorMessage* syncMessage = static_cast (message); - client->m_ClientTurnManager->OnSyncError(syncMessage->m_Turn, syncMessage->m_HashExpected, syncMessage->m_PlayerNames); - } - else if (message->GetType() == NMT_END_COMMAND_BATCH) - { - CEndCommandBatchMessage* endMessage = static_cast (message); - client->m_ClientTurnManager->FinishedAllCommands(endMessage->m_Turn, endMessage->m_TurnLength); - } + case NMT_SIMULATION_COMMAND: + { + CSimulationMessage simMessage(client->GetScriptInterface(), message); + client->m_ClientTurnManager->OnSimulationMessage(&simMessage); + break; + } + case NMT_SYNC_ERROR: + { + CSyncErrorMessage syncMessage(message); + client->m_ClientTurnManager->OnSyncError(syncMessage.m_Turn, syncMessage.m_HashExpected, syncMessage.m_PlayerNames); + break; + } + case NMT_END_COMMAND_BATCH: + { + CEndCommandBatchMessage endMessage(message); + client->m_ClientTurnManager->FinishedAllCommands(endMessage.m_Turn, endMessage.m_TurnLength); + break; + } } return true; Index: source/network/NetClientTurnManager.h =================================================================== --- source/network/NetClientTurnManager.h +++ source/network/NetClientTurnManager.h @@ -19,7 +19,7 @@ #define INCLUDED_NETCLIENTTURNMANAGER #include "simulation2/system/TurnManager.h" -#include "NetMessage.h" +#include "NetMessages.h" class CNetClient; @@ -41,7 +41,7 @@ */ void OnDestroyConnection(); - void OnSyncError(u32 turn, const CStr& expectedHash, const std::vector& playerNames); + void OnSyncError(u32 turn, const CStr& expectedHash, const std::vector& playerNames); private: void NotifyFinishedOwnCommands(u32 turn) override; Index: source/network/NetClientTurnManager.cpp =================================================================== --- source/network/NetClientTurnManager.cpp +++ source/network/NetClientTurnManager.cpp @@ -44,7 +44,7 @@ // Transmit command to server CSimulationMessage msg(m_Simulation2.GetScriptInterface(), m_ClientId, m_PlayerId, m_CurrentTurn + COMMAND_DELAY, data); - m_NetClient.SendMessage(&msg); + m_NetClient.SendMessage(msg); // Add to our local queue //AddCommand(m_ClientId, m_PlayerId, data, m_CurrentTurn + COMMAND_DELAY); @@ -64,7 +64,7 @@ // It could be used to verify that the client simulated the correct turn length. msg.m_TurnLength = 0; - m_NetClient.SendMessage(&msg); + m_NetClient.SendMessage(msg); } void CNetClientTurnManager::NotifyFinishedUpdate(u32 turn) @@ -88,7 +88,7 @@ CSyncCheckMessage msg; msg.m_Turn = turn; msg.m_Hash = hash; - m_NetClient.SendMessage(&msg); + m_NetClient.SendMessage(CNetMessageBuffer(msg)); } void CNetClientTurnManager::OnDestroyConnection() @@ -99,10 +99,10 @@ void CNetClientTurnManager::OnSimulationMessage(CSimulationMessage* msg) { // Command received from the server - store it for later execution - AddCommand(msg->m_Client, msg->m_Player, msg->m_Data, msg->m_Turn); + AddCommand(msg->m_Client, msg->m_Player, msg->m_JSData.m_Data, msg->m_Turn); } -void CNetClientTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, const std::vector& playerNames) +void CNetClientTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, const std::vector& playerNames) { CStr expectedHashHex(Hexify(expectedHash)); NETCLIENTTURN_LOG("OnSyncError(%d, %hs)\n", turn, expectedHashHex.c_str()); @@ -126,7 +126,7 @@ playerNamesStrings.reserve(playerNames.size()); for (size_t i = 0; i < playerNames.size(); ++i) { - CStr name = utf8_from_wstring(playerNames[i].m_Name); + CStr name = utf8_from_wstring(playerNames[i]); playerNamesString << (i == 0 ? "" : ", ") << name; playerNamesStrings.push_back(name); } Index: source/network/NetFileTransfer.h =================================================================== --- source/network/NetFileTransfer.h +++ source/network/NetFileTransfer.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,7 +20,7 @@ #include -class CNetMessage; +class CNetMessageBuffer; class CNetClientSession; class CNetServerSession; class INetSession; @@ -84,7 +84,7 @@ * Returns INFO::OK if the message is handled successfully, * or ERR::FAIL if handled unsuccessfully. */ - Status HandleMessageReceive(const CNetMessage* message); + Status HandleMessageReceive(const CNetMessageBuffer& message); /** * Registers a file-receiving task. Index: source/network/NetFileTransfer.cpp =================================================================== --- source/network/NetFileTransfer.cpp +++ source/network/NetFileTransfer.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -20,51 +20,53 @@ #include "NetFileTransfer.h" #include "lib/timer.h" -#include "network/NetMessage.h" +#include "network/NetMessages.h" #include "network/NetSession.h" #include "ps/CLogger.h" -Status CNetFileTransferer::HandleMessageReceive(const CNetMessage* message) +Status CNetFileTransferer::HandleMessageReceive(const CNetMessageBuffer& message) { - if (message->GetType() == NMT_FILE_TRANSFER_RESPONSE) + switch (message.GetType()) { - CFileTransferResponseMessage* respMessage = (CFileTransferResponseMessage*)message; + case NMT_FILE_TRANSFER_RESPONSE: + { + CFileTransferResponseMessage respMessage(message); - if (m_FileReceiveTasks.find(respMessage->m_RequestID) == m_FileReceiveTasks.end()) + if (m_FileReceiveTasks.find(respMessage.m_RequestID) == m_FileReceiveTasks.end()) { - LOGERROR("Net transfer: Unsolicited file transfer response (id=%d)", (int)respMessage->m_RequestID); + LOGERROR("Net transfer: Unsolicited file transfer response (id=%d)", (int)respMessage.m_RequestID); return ERR::FAIL; } - if (respMessage->m_Length == 0 || respMessage->m_Length > MAX_FILE_TRANSFER_SIZE) + if (respMessage.m_Length == 0 || respMessage.m_Length > MAX_FILE_TRANSFER_SIZE) { - LOGERROR("Net transfer: Invalid size for file transfer response (length=%d)", (int)respMessage->m_Length); + LOGERROR("Net transfer: Invalid size for file transfer response (length=%d)", (int)respMessage.m_Length); return ERR::FAIL; } - shared_ptr task = m_FileReceiveTasks[respMessage->m_RequestID]; + shared_ptr task = m_FileReceiveTasks[respMessage.m_RequestID]; - task->m_Length = respMessage->m_Length; - task->m_Buffer.reserve(respMessage->m_Length); + task->m_Length = respMessage.m_Length; + task->m_Buffer.reserve(respMessage.m_Length); LOGMESSAGERENDER("Downloading data over network (%d KB) - please wait...", (int)(task->m_Length/1024)); m_LastProgressReportTime = timer_Time(); return INFO::OK; } - else if (message->GetType() == NMT_FILE_TRANSFER_DATA) + case NMT_FILE_TRANSFER_DATA: { - CFileTransferDataMessage* dataMessage = (CFileTransferDataMessage*)message; + CFileTransferDataMessage dataMessage(message); - if (m_FileReceiveTasks.find(dataMessage->m_RequestID) == m_FileReceiveTasks.end()) + if (m_FileReceiveTasks.find(dataMessage.m_RequestID) == m_FileReceiveTasks.end()) { - LOGERROR("Net transfer: Unsolicited file transfer data (id=%d)", (int)dataMessage->m_RequestID); + LOGERROR("Net transfer: Unsolicited file transfer data (id=%d)", (int)dataMessage.m_RequestID); return ERR::FAIL; } - shared_ptr task = m_FileReceiveTasks[dataMessage->m_RequestID]; + shared_ptr task = m_FileReceiveTasks[dataMessage.m_RequestID]; - task->m_Buffer += dataMessage->m_Data; + task->m_Buffer += dataMessage.m_Data; if (task->m_Buffer.size() > task->m_Length) { @@ -75,14 +77,14 @@ CFileTransferAckMessage ackMessage; ackMessage.m_RequestID = task->m_RequestID; ackMessage.m_NumPackets = 1; // TODO: would be nice to send a single ack for multiple packets at once - m_Session->SendMessage(&ackMessage); + m_Session->SendMessage(ackMessage); if (task->m_Buffer.size() == task->m_Length) { LOGMESSAGERENDER("Download completed"); task->OnComplete(); - m_FileReceiveTasks.erase(dataMessage->m_RequestID); + m_FileReceiveTasks.erase(dataMessage.m_RequestID); return INFO::OK; } @@ -98,29 +100,30 @@ return INFO::OK; } - else if (message->GetType() == NMT_FILE_TRANSFER_ACK) + case NMT_FILE_TRANSFER_ACK: { - CFileTransferAckMessage* ackMessage = (CFileTransferAckMessage*)message; + CFileTransferAckMessage ackMessage(message); - if (m_FileSendTasks.find(ackMessage->m_RequestID) == m_FileSendTasks.end()) + if (m_FileSendTasks.find(ackMessage.m_RequestID) == m_FileSendTasks.end()) { - LOGERROR("Net transfer: Unsolicited file transfer ack (id=%d)", (int)ackMessage->m_RequestID); + LOGERROR("Net transfer: Unsolicited file transfer ack (id=%d)", (int)ackMessage.m_RequestID); return ERR::FAIL; } - CNetFileSendTask& task = m_FileSendTasks[ackMessage->m_RequestID]; + CNetFileSendTask& task = m_FileSendTasks[ackMessage.m_RequestID]; - if (ackMessage->m_NumPackets > task.packetsInFlight) + if (ackMessage.m_NumPackets > task.packetsInFlight) { LOGERROR("Net transfer: Invalid num packets for file transfer ack (num=%d inflight=%d)", - (int)ackMessage->m_NumPackets, (int)task.packetsInFlight); + (int)ackMessage.m_NumPackets, (int)task.packetsInFlight); return ERR::FAIL; } - task.packetsInFlight -= ackMessage->m_NumPackets; + task.packetsInFlight -= ackMessage.m_NumPackets; return INFO::OK; } + } return INFO::SKIPPED; } @@ -135,7 +138,7 @@ CFileTransferRequestMessage request; request.m_RequestID = requestID; - m_Session->SendMessage(&request); + m_Session->SendMessage(request); } void CNetFileTransferer::StartResponse(u32 requestID, const std::string& data) @@ -151,7 +154,7 @@ CFileTransferResponseMessage respMessage; respMessage.m_RequestID = requestID; respMessage.m_Length = task.buffer.size(); - m_Session->SendMessage(&respMessage); + m_Session->SendMessage(respMessage); } void CNetFileTransferer::Poll() @@ -170,7 +173,7 @@ dataMessage.m_Data = task.buffer.substr(task.offset, packetSize); task.offset += packetSize; ++task.packetsInFlight; - m_Session->SendMessage(&dataMessage); + m_Session->SendMessage(dataMessage); } } Index: source/network/NetHost.h =================================================================== --- source/network/NetHost.h +++ source/network/NetHost.h @@ -30,7 +30,7 @@ typedef struct _ENetPeer ENetPeer; typedef struct _ENetPacket ENetPacket; typedef struct _ENetHost ENetHost; -class CNetMessage; +class CNetMessageBuffer; struct PlayerAssignment { @@ -83,13 +83,13 @@ * @param peerName name of peer for debug logs * @return true on success, false on failure */ - static bool SendMessage(const CNetMessage* message, ENetPeer* peer, const char* peerName); + static bool SendMessage(const CNetMessageBuffer& message, ENetPeer* peer, const char* peerName); /** - * Construct an ENet packet by serialising the given message. + * Construct an ENet packet from the given message. * @return NULL on failure */ - static ENetPacket* CreatePacket(const CNetMessage* message); + static ENetPacket* CreatePacket(const CNetMessageBuffer& message); /** * Initialize ENet. Index: source/network/NetHost.cpp =================================================================== --- source/network/NetHost.cpp +++ source/network/NetHost.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,18 +18,17 @@ #include "precompiled.h" #include "NetHost.h" - +#include "NetMessageBuffer.h" #include "lib/external_libraries/enet.h" -#include "network/NetMessage.h" #include "ps/CLogger.h" -bool CNetHost::SendMessage(const CNetMessage* message, ENetPeer* peer, const char* peerName) +bool CNetHost::SendMessage(const CNetMessageBuffer& message, ENetPeer* peer, const char* peerName) { ENetPacket* packet = CreatePacket(message); if (!packet) return false; - LOGMESSAGE("Net: Sending message %s of size %lu to %s", message->ToString().c_str(), (unsigned long)packet->dataLength, peerName); + LOGMESSAGE("Net: Sending message of size %lu to %s", (unsigned long)packet->dataLength, peerName); // Let ENet send the message to peer if (enet_peer_send(peer, DEFAULT_CHANNEL, packet) < 0) @@ -46,21 +45,10 @@ return true; } -ENetPacket* CNetHost::CreatePacket(const CNetMessage* message) +ENetPacket* CNetHost::CreatePacket(const CNetMessageBuffer& message) { - size_t size = message->GetSerializedLength(); - - ENSURE(size); // else we'll fail when accessing the 0th element - - // Adjust buffer for message - std::vector buffer; - buffer.resize(size); - - // Save message to internal buffer - message->Serialize(&buffer[0]); - // Create a reliable packet - ENetPacket* packet = enet_packet_create(&buffer[0], size, ENET_PACKET_FLAG_RELIABLE); + ENetPacket* packet = enet_packet_create(message.GetData(), message.GetSize(), ENET_PACKET_FLAG_RELIABLE); if (!packet) LOGERROR("Net: Failed to construct packet"); Index: source/network/NetMessage.h =================================================================== --- source/network/NetMessage.h +++ /dev/null @@ -1,160 +0,0 @@ -/* Copyright (C) 2015 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#ifndef NETMESSAGE_H -#define NETMESSAGE_H - -#include "Serialization.h" - -// We need the enum from NetMessages.h, but we can't create any classes in -// NetMessages.h, since they in turn require CNetMessage to be defined -#define ALLNETMSGS_DONT_CREATE_NMTS -#include "NetMessages.h" -#undef ALLNETMSGS_DONT_CREATE_NMTS - -/** - * The base class for all network messages exchanged within the game. - */ -class CNetMessage : public ISerializable -{ - friend class CNetSession; - -public: - - CNetMessage(); - CNetMessage(NetMessageType type); - virtual ~CNetMessage(); - - /** - * Retrieves the message type. - * @return Message type - */ - NetMessageType GetType() const { return m_Type; } - - /** - * Serialize the message into the specified buffer parameter. The size - * required by the buffer parameter can be found by a call to - * GetSerializedLength method. The information contained within the message - * must be serialized before the message is sent. By default only the - * message type and its size are serialized in the buffer parameter. - * - * @param pBuffer Buffer where to serialize the message - * @return The position in the buffer right after the - * serialized message - */ - virtual u8* Serialize(u8* pBuffer) const; - - /** - * Deserializes the message from the specified buffer. - * - * @param pStart Message start within the serialized buffer - * @param pEnd Message end within the serialized buffer - * @return The position in the buffer right after the - * message or NULL if an error occured - */ - virtual const u8* Deserialize(const u8* pStart, const u8* pEnd); - - /** - * Retrieves the size in bytes of the serialized message. Before calling - * Serialize, the memory size for the buffer where to serialize the message - * object can be found by calling this method. - * - * @return The size of serialized message - */ - virtual size_t GetSerializedLength() const; - - /** - * Returns a string representation for the message - * - * @return The message as a string - */ - virtual CStr ToString() const; - -private: - NetMessageType m_Type; // Message type -}; - -/** - * Creates messages from data received through the network. - */ -class CNetMessageFactory -{ -public: - - /** - * Factory method which creates a message object based on the given data - * - * @param pData Data buffer - * @param dataSize Size of data buffer - * @param scriptInterface Script instance to use when constructing scripted messages - * @return The new message created - */ - static CNetMessage* CreateMessage(const void* pData, size_t dataSize, ScriptInterface& scriptInterface); -}; - -/** - * Special message type for simulation commands. - * These commands are exposed as arbitrary JS objects, associated with a specific player. - */ -class CSimulationMessage : public CNetMessage -{ -public: - CSimulationMessage(ScriptInterface& scriptInterface); - CSimulationMessage(ScriptInterface& scriptInterface, u32 client, i32 player, u32 turn, JS::HandleValue data); - - /** The compiler can't create a copy constructor because of the PersistentRooted member, - * so we have to write it manually. - * NOTE: It doesn't clone the m_Data member and the copy will reference the same JS::Value! - */ - CSimulationMessage(const CSimulationMessage& orig); - - virtual u8* Serialize(u8* pBuffer) const; - virtual const u8* Deserialize(const u8* pStart, const u8* pEnd); - virtual size_t GetSerializedLength() const; - virtual CStr ToString() const; - - u32 m_Client; - i32 m_Player; - u32 m_Turn; - JS::PersistentRooted m_Data; -private: - ScriptInterface* m_ScriptInterface; -}; - -/** - * Special message type for updated to game startup settings. - */ -class CGameSetupMessage : public CNetMessage -{ - NONCOPYABLE(CGameSetupMessage); -public: - CGameSetupMessage(ScriptInterface& scriptInterface); - CGameSetupMessage(ScriptInterface& scriptInterface, JS::HandleValue data); - virtual u8* Serialize(u8* pBuffer) const; - virtual const u8* Deserialize(const u8* pStart, const u8* pEnd); - virtual size_t GetSerializedLength() const; - virtual CStr ToString() const; - - JS::PersistentRootedValue m_Data; -private: - ScriptInterface& m_ScriptInterface; -}; - -// This time, the classes are created -#include "NetMessages.h" - -#endif // NETMESSAGE_H Index: source/network/NetMessage.cpp =================================================================== --- source/network/NetMessage.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* Copyright (C) 2017 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#include "precompiled.h" -#include "NetMessage.h" - -#include "ps/CLogger.h" - -#include "ps/Game.h" -#include "simulation2/Simulation2.h" - -#undef ALLNETMSGS_DONT_CREATE_NMTS -#define ALLNETMSGS_IMPLEMENT -#include "NetMessages.h" - -CNetMessage::CNetMessage() -{ - m_Type = NMT_INVALID; -} - -CNetMessage::CNetMessage(NetMessageType type) -{ - m_Type = type; -} - -CNetMessage::~CNetMessage() -{ -} - -u8* CNetMessage::Serialize(u8* pBuffer) const -{ - size_t size = GetSerializedLength(); - Serialize_int_1(pBuffer, m_Type); - Serialize_int_2(pBuffer, size); - - return pBuffer; -} - -const u8* CNetMessage::Deserialize(const u8* pStart, const u8* pEnd) -{ - if (pStart + 3 > pEnd) - { - LOGERROR("CNetMessage: Corrupt packet (smaller than header)"); - return NULL; - } - - const u8* pBuffer = pStart; - - int type; - size_t size; - Deserialize_int_1(pBuffer, type); - Deserialize_int_2(pBuffer, size); - m_Type = (NetMessageType)type; - - if (pStart + size != pEnd) - { - LOGERROR("CNetMessage: Corrupt packet (incorrect size)"); - return NULL; - } - - return pBuffer; -} - -size_t CNetMessage::GetSerializedLength() const -{ - // By default, return header size - return 3; -} - -CStr CNetMessage::ToString() const -{ - // This is called only when the subclass doesn't override it - - if (GetType() == NMT_INVALID) - return "MESSAGE_TYPE_NONE { Undefined Message }"; - else - return "Unknown Message " + CStr::FromInt(GetType()); -} - -CNetMessage* CNetMessageFactory::CreateMessage(const void* pData, - size_t dataSize, - ScriptInterface& scriptInterface) -{ - CNetMessage* pNewMessage = NULL; - CNetMessage header; - - // Figure out message type - header.Deserialize((const u8*)pData, (const u8*)pData + dataSize); - - switch (header.GetType()) - { - case NMT_GAME_SETUP: - pNewMessage = new CGameSetupMessage(scriptInterface); - break; - - case NMT_PLAYER_ASSIGNMENT: - pNewMessage = new CPlayerAssignmentMessage; - break; - - case NMT_FILE_TRANSFER_REQUEST: - pNewMessage = new CFileTransferRequestMessage; - break; - - case NMT_FILE_TRANSFER_RESPONSE: - pNewMessage = new CFileTransferResponseMessage; - break; - - case NMT_FILE_TRANSFER_DATA: - pNewMessage = new CFileTransferDataMessage; - break; - - case NMT_FILE_TRANSFER_ACK: - pNewMessage = new CFileTransferAckMessage; - break; - - case NMT_JOIN_SYNC_START: - pNewMessage = new CJoinSyncStartMessage; - break; - - case NMT_REJOINED: - pNewMessage = new CRejoinedMessage; - break; - - case NMT_KICKED: - pNewMessage = new CKickedMessage; - break; - - case NMT_CLIENT_TIMEOUT: - pNewMessage = new CClientTimeoutMessage; - break; - - case NMT_CLIENT_PERFORMANCE: - pNewMessage = new CClientPerformanceMessage; - break; - - case NMT_CLIENTS_LOADING: - pNewMessage = new CClientsLoadingMessage; - break; - - case NMT_CLIENT_PAUSED: - pNewMessage = new CClientPausedMessage; - break; - - case NMT_LOADED_GAME: - pNewMessage = new CLoadedGameMessage; - break; - - case NMT_SERVER_HANDSHAKE: - pNewMessage = new CSrvHandshakeMessage; - break; - - case NMT_SERVER_HANDSHAKE_RESPONSE: - pNewMessage = new CSrvHandshakeResponseMessage; - break; - - case NMT_CLIENT_HANDSHAKE: - pNewMessage = new CCliHandshakeMessage; - break; - - case NMT_AUTHENTICATE: - pNewMessage = new CAuthenticateMessage; - break; - - case NMT_AUTHENTICATE_RESULT: - pNewMessage = new CAuthenticateResultMessage; - break; - - case NMT_GAME_START: - pNewMessage = new CGameStartMessage; - break; - - case NMT_END_COMMAND_BATCH: - pNewMessage = new CEndCommandBatchMessage; - break; - - case NMT_SYNC_CHECK: - pNewMessage = new CSyncCheckMessage; - break; - - case NMT_SYNC_ERROR: - pNewMessage = new CSyncErrorMessage; - break; - - case NMT_CHAT: - pNewMessage = new CChatMessage; - break; - - case NMT_READY: - pNewMessage = new CReadyMessage; - break; - - case NMT_SIMULATION_COMMAND: - pNewMessage = new CSimulationMessage(scriptInterface); - break; - - case NMT_CLEAR_ALL_READY: - pNewMessage = new CClearAllReadyMessage; - break; - - case NMT_ASSIGN_PLAYER: - pNewMessage = new CAssignPlayerMessage; - break; - - default: - LOGERROR("CNetMessageFactory::CreateMessage(): Unknown message type '%d' received", header.GetType()); - break; - } - - if (pNewMessage) - pNewMessage->Deserialize((const u8*)pData, (const u8*)pData + dataSize); - - return pNewMessage; -} Index: source/network/NetMessageBuffer.h =================================================================== --- /dev/null +++ source/network/NetMessageBuffer.h @@ -0,0 +1,413 @@ +/* Copyright (C) 2017 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#ifndef NETMESSAGEBUFFER_H +#define NETMESSAGEBUFFER_H + +#include "NetMessageType.h" +#include "ps/CStr.h" +#include "scriptinterface/ScriptInterface.h" + +#include + +/** + * This file deals with storing net messages in a serialized state, + * and serializing / deserializing them. Note that in this file, + * a "serialization primitive" refers to one of: + * - an integer + * - std::vector + * - std::array + * - CStr or CStrW + * - SerializableJSValue + * whereas a compound object refers to a structure potentially containing multiple objects of these types which + * can be serialized (and inherits from ISerializable. + */ + +/** + * Should be used to tag objects that define a const and non-const RegisterSerializable function of signatures: + * @code + * template + * struct RegisterSerializable(Func func); + * template + * struct RegisterSerializable(Func func) const; + * @endcode + * which executes the parameter on every member which needs to be serialized. + * It is recommended to use the REGISTER_SERIALIZABLE(...) and REGISTER_SERIALIZABLE_EMPTY() to generate these + * functions. + */ +class ISerializable {}; + +/** + * Defines both the constant and non constant version of the RegisterSerializable functions. + */ +#define REGISTER_SERIALIZABLE(...) \ + template \ + void RegisterSerializable(Func registerFunction) { registerFunction(__VA_ARGS__); } \ + template \ + void RegisterSerializable(Func registerFunction) const { registerFunction(__VA_ARGS__); } + +/** + * Does the same thing as REGISTER_SERIALIZABLE, but doesn't serialize any members of the class + * (that is, only the size and type will be serialized). + */ +#define REGISTER_SERIALIZABLE_EMPTY() \ + template \ + void RegisterSerializable(Func) {} \ + template \ + void RegisterSerializable(Func) const {} + +#define BEGIN_SERIALIZABLE(typeName) \ + struct typeName : ISerializable { \ + +#define END_SERIALIZABLE() }; + +#define BEGIN_NETMESSAGE_WITH_CUSTOM_CONSTRUCTOR(typeName, nmType) \ + class typeName : ISerializable { \ + public: \ + static const NetMessageType type = nmType; + +#define END_NETMESSAGE_WITH_CUSTOM_CONSTRUCTOR() }; + +#define BEGIN_NETMESSAGE(typeName, nmType) \ + class typeName : ISerializable { \ + public: \ + static const NetMessageType type = nmType; \ + typeName() {} \ + typeName(const CNetMessageBuffer& buffer) { buffer.GetMessage(*this); } + +#define END_NETMESSAGE() }; + +struct SerializableJSValue +{ + SerializableJSValue(ScriptInterface& interface) : + m_ScriptInterface(interface), + m_Data(interface.GetJSRuntime()) + { + } + + SerializableJSValue(ScriptInterface& interface, JS::HandleValue data) : + m_ScriptInterface(interface), + m_Data(interface.GetJSRuntime(), data) + { + } + + ScriptInterface& m_ScriptInterface; + JS::PersistentRootedValue m_Data; +}; + +/** + * Represents a serialized net message. The SerializableObject type used in it + * refers to the class type locally representing the message, and it is expected to derive from ISerializable. + * Additionally it is expected to contain a static constant "type" which holds the associated NetMessageType. + */ +class CNetMessageBuffer +{ +public: + CNetMessageBuffer(); + + /** + * Serializes the given object into the buffer. + */ + template + CNetMessageBuffer(const SerializableObject& object) + { + m_Type = object.type; + + // The first 5 bytes of the buffer are reserved for the type (1 byte) and the size (4 bytes) of the message. + ToPosition(HEADER_SIZE); + SerializeCompoundFunctor serializer{*this}; + serializer(object); + + ToPosition(0); + SerializePrimitive((u8)object.type); + SerializePrimitive((u32)m_Buffer.size()); + } + + CNetMessageBuffer(const std::vector& buffer); + CNetMessageBuffer(u8* buffer, u32 size); + + NetMessageType GetType() const + { + return m_Type; + } + + const u8* GetData() const + { + ENSURE(!m_Buffer.empty()); + return m_Buffer.data(); + } + + size_t GetSize() const + { + return m_Buffer.size(); + } + + /** + * Does this buffer hold a valid message? + */ + explicit operator bool() const + { + return m_Type != NMT_INVALID && m_Buffer.size() >= HEADER_SIZE; + } + + /** + * Deserializes the buffer into the given object. + */ + template + void GetMessage(SerializableObject& object) const + { + ENSURE(object.type == m_Type); + + ToPosition(1); + u32 size; + DeserializePrimitive(size); + ENSURE(size == m_Buffer.size()); + + DeserializeCompoundFunctor deserializer{*this}; + deserializer(object); + } + +private: + void ToPosition(u32 pos); + + /** + * const as it doesn't allow enlarging the buffer. + */ + void ToPosition(u32 pos) const; + + /** + * Write a byte and advance the current position. + */ + void Write(u8 byte); + + /** + * Reads at the current position and advances the position. + */ + u8 Read() const; + + /** + * Serialization function which allows serializing both compound types and serialization primitives. + */ + template + void Serialize(const T& object) + { + typename std::conditional::value, SerializeCompoundFunctor, SerializePrimitiveFunctor>::type serializer{*this}; + serializer(object); + } + + /** + * Serialize an integer, std::vector, std::array, CStr, CStrW or a SerializableJSValue. + * Note that we can serialize integers in a general way and catch all other types using @ref SerializeNonInteger. + */ + template + void SerializePrimitive(const T& object) + { + for (u32 i = 0; i < sizeof(T); ++i) + { + Write(object >> i * 8 & 0xff); + } + } + + template + void SerializePrimitive(const std::array& object) + { + static_assert(object.size() < std::numeric_limits::max(), "size of std::array needs to be smaller than u32 max in order to be serialized."); + + SerializePrimitive((u32)object.size()); + for (u32 i = 0; i < object.size(); ++i) + { + Serialize(object[i]); + } + } + + template + void SerializePrimitive(const std::vector& object) + { + ENSURE(object.size() < std::numeric_limits::max()); + + SerializePrimitive((u32)object.size()); + for (u32 i = 0; i < object.size(); ++i) + { + Serialize(object[i]); + } + } + + /** + * Allows deserializing both compound types and serialization primitives. + */ + template + void Deserialize(T& object) const + { + typename std::conditional::value, DeserializeCompoundFunctor, DeserializePrimitiveFunctor>::type deserializer{*this}; + deserializer(object); + } + + template + void DeserializePrimitive(T& object) const + { + object = T(0); + for (u32 i = 0; i < sizeof(T); ++i) + { + object |= (T)Read() << i * 8; + } + } + + template + void DeserializePrimitive(std::array& object) const + { + u32 size; + DeserializePrimitive(size); + ENSURE(size == object.size()); + for (u32 i = 0; i < object.size(); ++i) + { + Deserialize(object[i]); + } + } + + template + void DeserializePrimitive(std::vector& object) const + { + u32 size; + DeserializePrimitive(size); + object.resize(size); + for (u32 i = 0; i < object.size(); ++i) + { + Deserialize(object[i]); + } + } + + /** + * Serializes an "ISerializable" object. This allows us to select the right function to use at compile time in Serialize (this or SerializePrimitiveFunctor). + */ + struct SerializeCompoundFunctor + { + template + void operator()(const T& object) const + { + static_assert(std::is_base_of::value, "SerializeCompoundFunctor expects a subclass of ISerializable."); + SerializeFunctor serializer{m_Buffer}; + object.RegisterSerializable(serializer); + } + + CNetMessageBuffer& m_Buffer; + }; + + struct SerializePrimitiveFunctor + { + template + void operator()(const T& object) const + { + m_Buffer.SerializePrimitive(object); + } + + CNetMessageBuffer& m_Buffer; + }; + + /** + * Functor which should be used for the call to RegisterSerializable on compound objects. + */ + struct SerializeFunctor + { + template + void operator()(const T& object) const + { + m_Buffer.Serialize(object); + } + + /** + * For ease of use, also provide a variadic version. + */ + template + void operator()(const T& object, const Args&... args) const + { + (*this)(object); + (*this)(args...); + } + + CNetMessageBuffer& m_Buffer; + }; + + struct DeserializeCompoundFunctor + { + template + void operator()(T& object) const + { + static_assert(std::is_base_of::value, "DeserializeCompoundFunctor expects a subclass of ISerializable."); + DeserializeFunctor deserializer{m_Buffer}; + object.RegisterSerializable(deserializer); + } + + const CNetMessageBuffer& m_Buffer; + }; + + struct DeserializePrimitiveFunctor + { + template + void operator()(T& object) const + { + m_Buffer.DeserializePrimitive(object); + } + + const CNetMessageBuffer& m_Buffer; + }; + + struct DeserializeFunctor + { + template + void operator()(T& object) const + { + m_Buffer.Deserialize(object); + } + + template + void operator()(T& object, Args&... args) const + { + (*this)(object); + (*this)(args...); + } + + const CNetMessageBuffer& m_Buffer; + }; + + static const u32 HEADER_SIZE = 5; + std::vector m_Buffer; + mutable u32 m_Position; + NetMessageType m_Type; +}; + +template<> +void CNetMessageBuffer::Serialize(const CStr& object); + +/** + * CStrW always serializes to u16. + */ +template<> +void CNetMessageBuffer::Serialize(const CStrW& object); + +template<> +void CNetMessageBuffer::Serialize(const SerializableJSValue& object); + +template<> +void CNetMessageBuffer::Deserialize(CStr& object) const; + +template<> +void CNetMessageBuffer::Deserialize(CStrW& object) const; + +template<> +void CNetMessageBuffer::Deserialize(SerializableJSValue& object) const; + +#endif // NETMESSAGEBUFFER_H Index: source/network/NetMessageBuffer.cpp =================================================================== --- /dev/null +++ source/network/NetMessageBuffer.cpp @@ -0,0 +1,174 @@ +/* Copyright (C) 2017 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "NetMessageBuffer.h" + +#include "simulation2/serialization/BinarySerializer.h" +#include "simulation2/serialization/StdDeserializer.h" + +CNetMessageBuffer::CNetMessageBuffer() : + m_Buffer(), + m_Position(0), + m_Type(NMT_INVALID) +{ +} + +CNetMessageBuffer::CNetMessageBuffer(const std::vector& buffer) : + m_Buffer(buffer), + m_Position(0), + m_Type((NetMessageType)Read()) +{ +} + +CNetMessageBuffer::CNetMessageBuffer(u8* buffer, u32 size) : + m_Buffer(), + m_Position(0), + m_Type() +{ + m_Buffer.resize(size); + std::memcpy(m_Buffer.data(), buffer, size); + m_Type = (NetMessageType)Read(); +} + +void CNetMessageBuffer::ToPosition(u32 pos) +{ + if (pos >= m_Buffer.size()) + m_Buffer.resize(pos + 1); + + m_Position = pos; +} + +void CNetMessageBuffer::ToPosition(u32 pos) const +{ + ENSURE(pos < m_Buffer.size()); + + m_Position = pos; +} + +void CNetMessageBuffer::Write(u8 byte) +{ + ENSURE(m_Position < std::numeric_limits::max()); + if (m_Position >= m_Buffer.size()) + m_Buffer.resize(m_Position + 1); + + m_Buffer[m_Position++] = byte; +} + +u8 CNetMessageBuffer::Read() const +{ + ENSURE(m_Position < m_Buffer.size()); + return m_Buffer[m_Position++]; +} + +class CBufferBinarySerializerImpl +{ +public: + CBufferBinarySerializerImpl() : + m_Buffer() + { + } + + void Put(const char* UNUSED(name), const u8* data, size_t len) + { + size_t pos = m_Buffer.size(); + m_Buffer.resize(m_Buffer.size() + len); + std::memcpy(m_Buffer.data() + pos, data, len); + } + + std::vector m_Buffer; +}; + +class CBufferBinarySerializer : public CBinarySerializer +{ +public: + CBufferBinarySerializer(ScriptInterface& scriptInterface) : + CBinarySerializer(scriptInterface) + { + } + + const std::vector& GetBuffer() const + { + return m_Impl.m_Buffer; + } +}; + +template<> +void CNetMessageBuffer::Serialize(const CStr& object) +{ + SerializePrimitive((u32)object.size()); + for (u32 i = 0; i < object.size(); ++i) + { + SerializePrimitive(object[i]); + } +} + +template<> +void CNetMessageBuffer::Serialize(const CStrW& object) +{ + SerializePrimitive((u32)object.size()); + for (u32 i = 0; i < object.size(); ++i) + { + SerializePrimitive((u16)object[i]); + } +} + +template<> +void CNetMessageBuffer::Serialize(const SerializableJSValue& object) +{ + CBufferBinarySerializer serializer(object.m_ScriptInterface); + serializer.ScriptVal("command", const_cast(&object.m_Data)); + std::vector buffer = serializer.GetBuffer(); + SerializePrimitive(buffer); +} + +template<> +void CNetMessageBuffer::Deserialize(CStr& object) const +{ + u32 size; + DeserializePrimitive(size); + object.resize(size); + for (u32 i = 0; i < size; ++i) + { + DeserializePrimitive(object[i]); + } +} + +template<> +void CNetMessageBuffer::Deserialize(CStrW& object) const +{ + u32 size; + DeserializePrimitive(size); + object.resize(size); + for (u32 i = 0; i < size; ++i) + { + u16 tmp; + DeserializePrimitive(tmp); + object[i] = tmp; + } +} + +template<> +void CNetMessageBuffer::Deserialize(SerializableJSValue& object) const +{ + std::vector buffer; + DeserializePrimitive(buffer); + std::istringstream stream(std::string(buffer.begin(), buffer.end())); + CStdDeserializer deserializer(object.m_ScriptInterface, stream); + deserializer.ScriptVal("command", &object.m_Data); +} Index: source/network/NetMessageSim.cpp =================================================================== --- source/network/NetMessageSim.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* Copyright (C) 2011 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#include "precompiled.h" - -#include "NetMessage.h" - -#include "lib/utf8.h" -#include "scriptinterface/ScriptInterface.h" -#include "simulation2/serialization/BinarySerializer.h" -#include "simulation2/serialization/StdDeserializer.h" -#include "simulation2/serialization/StdSerializer.h" // for DEBUG_SERIALIZER_ANNOTATE - -#include - -class CBufferBinarySerializerImpl -{ -public: - CBufferBinarySerializerImpl(u8* buffer) : - m_Buffer(buffer) - { - } - - void Put(const char* name, const u8* data, size_t len) - { - #if DEBUG_SERIALIZER_ANNOTATE - std::string tag = "<"; - tag.append(name); - tag.append(">"); - memcpy(m_Buffer, tag.c_str(), tag.length()); - m_Buffer += tag.length(); - #else - UNUSED2(name); - #endif - memcpy(m_Buffer, data, len); - m_Buffer += len; - } - - u8* m_Buffer; -}; - -/** - * Serializer instance that writes directly to a buffer (which must be long enough). - */ -class CBufferBinarySerializer : public CBinarySerializer -{ -public: - CBufferBinarySerializer(ScriptInterface& scriptInterface, u8* buffer) : - CBinarySerializer(scriptInterface, buffer) - { - } - - u8* GetBuffer() - { - return m_Impl.m_Buffer; - } -}; - -class CLengthBinarySerializerImpl -{ -public: - CLengthBinarySerializerImpl() : - m_Length(0) - { - } - - void Put(const char* name, const u8* UNUSED(data), size_t len) - { - #if DEBUG_SERIALIZER_ANNOTATE - m_Length += 2; // '<' and '>' - m_Length += strlen(name); - #else - UNUSED2(name); - #endif - m_Length += len; - } - - size_t m_Length; -}; - -/** - * Serializer instance that simply counts how many bytes would be written. - */ -class CLengthBinarySerializer : public CBinarySerializer -{ -public: - CLengthBinarySerializer(ScriptInterface& scriptInterface) : - CBinarySerializer(scriptInterface) - { - } - - size_t GetLength() - { - return m_Impl.m_Length; - } -}; - -CSimulationMessage::CSimulationMessage(ScriptInterface& scriptInterface) : - CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(&scriptInterface), m_Data(scriptInterface.GetJSRuntime()) -{ -} - -CSimulationMessage::CSimulationMessage(ScriptInterface& scriptInterface, u32 client, i32 player, u32 turn, JS::HandleValue data) : - CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(&scriptInterface), - m_Client(client), m_Player(player), m_Turn(turn), m_Data(scriptInterface.GetJSRuntime(), data) -{ -} - -CSimulationMessage::CSimulationMessage(const CSimulationMessage& orig) : - m_Data(orig.m_ScriptInterface->GetJSRuntime()), - m_Client(orig.m_Client), - m_Player(orig.m_Player), - m_ScriptInterface(orig.m_ScriptInterface), - m_Turn(orig.m_Turn), - CNetMessage(orig) -{ - m_Data = orig.m_Data; -} - -u8* CSimulationMessage::Serialize(u8* pBuffer) const -{ - // TODO: ought to handle serialization exceptions - // TODO: ought to represent common commands more efficiently - u8* pos = CNetMessage::Serialize(pBuffer); - CBufferBinarySerializer serializer(*m_ScriptInterface, pos); - serializer.NumberU32_Unbounded("client", m_Client); - serializer.NumberI32_Unbounded("player", m_Player); - serializer.NumberU32_Unbounded("turn", m_Turn); - - serializer.ScriptVal("command", const_cast(&m_Data)); - return serializer.GetBuffer(); -} - -const u8* CSimulationMessage::Deserialize(const u8* pStart, const u8* pEnd) -{ - // TODO: ought to handle serialization exceptions - // TODO: ought to represent common commands more efficiently - const u8* pos = CNetMessage::Deserialize(pStart, pEnd); - std::istringstream stream(std::string(pos, pEnd)); - CStdDeserializer deserializer(*m_ScriptInterface, stream); - deserializer.NumberU32_Unbounded("client", m_Client); - deserializer.NumberI32_Unbounded("player", m_Player); - deserializer.NumberU32_Unbounded("turn", m_Turn); - deserializer.ScriptVal("command", &m_Data); - return pEnd; -} - -size_t CSimulationMessage::GetSerializedLength() const -{ - // TODO: serializing twice is stupidly inefficient - we should just - // do it once, store the result, and use it here and in Serialize - CLengthBinarySerializer serializer(*m_ScriptInterface); - serializer.NumberU32_Unbounded("client", m_Client); - serializer.NumberI32_Unbounded("player", m_Player); - serializer.NumberU32_Unbounded("turn", m_Turn); - - // TODO: The cast can probably be removed if and when ScriptVal can take a JS::HandleValue instead of - // a JS::MutableHandleValue (relies on JSAPI change). Also search for other casts like this one in that case. - serializer.ScriptVal("command", const_cast(&m_Data)); - return CNetMessage::GetSerializedLength() + serializer.GetLength(); -} - -CStr CSimulationMessage::ToString() const -{ - std::string source = m_ScriptInterface->ToString(const_cast(&m_Data)); - - std::stringstream stream; - stream << "CSimulationMessage { m_Client: " << m_Client << ", m_Player: " << m_Player << ", m_Turn: " << m_Turn << ", m_Data: " << source << " }"; - return CStr(stream.str()); -} - - -CGameSetupMessage::CGameSetupMessage(ScriptInterface& scriptInterface) : - CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface), m_Data(scriptInterface.GetJSRuntime()) -{ -} - -CGameSetupMessage::CGameSetupMessage(ScriptInterface& scriptInterface, JS::HandleValue data) : - CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface), - m_Data(scriptInterface.GetJSRuntime(), data) -{ -} - -u8* CGameSetupMessage::Serialize(u8* pBuffer) const -{ - // TODO: ought to handle serialization exceptions - u8* pos = CNetMessage::Serialize(pBuffer); - CBufferBinarySerializer serializer(m_ScriptInterface, pos); - serializer.ScriptVal("command", const_cast(&m_Data)); - return serializer.GetBuffer(); -} - -const u8* CGameSetupMessage::Deserialize(const u8* pStart, const u8* pEnd) -{ - // TODO: ought to handle serialization exceptions - const u8* pos = CNetMessage::Deserialize(pStart, pEnd); - std::istringstream stream(std::string(pos, pEnd)); - CStdDeserializer deserializer(m_ScriptInterface, stream); - deserializer.ScriptVal("command", const_cast(&m_Data)); - return pEnd; -} - -size_t CGameSetupMessage::GetSerializedLength() const -{ - CLengthBinarySerializer serializer(m_ScriptInterface); - serializer.ScriptVal("command", const_cast(&m_Data)); - return CNetMessage::GetSerializedLength() + serializer.GetLength(); -} - -CStr CGameSetupMessage::ToString() const -{ - std::string source = m_ScriptInterface.ToString(const_cast(&m_Data)); - - std::stringstream stream; - stream << "CGameSetupMessage { m_Data: " << source << " }"; - return CStr(stream.str()); -} Index: source/network/NetMessageType.h =================================================================== --- /dev/null +++ source/network/NetMessageType.h @@ -0,0 +1,72 @@ +/* Copyright (C) 2017 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. 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 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. 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 0 A.D. If not, see . + */ + +#ifndef NETMESSAGETYPE_H +#define NETMESSAGETYPE_H + +/** + * Defines the list of message types. The order of the list must not change. + * The message types having a negative value are used internally and not sent + * over the network. The message types used for network communication have + * positive values. + */ +enum NetMessageType +{ + NMT_CONNECT_COMPLETE = -256, + NMT_CONNECTION_LOST, + NMT_INVALID = 0, + + NMT_SERVER_HANDSHAKE, + NMT_CLIENT_HANDSHAKE, + NMT_SERVER_HANDSHAKE_RESPONSE, + + NMT_AUTHENTICATE, + NMT_AUTHENTICATE_RESULT, + + NMT_CHAT, + NMT_READY, + NMT_CLEAR_ALL_READY, + NMT_GAME_SETUP, + NMT_ASSIGN_PLAYER, + NMT_PLAYER_ASSIGNMENT, + + NMT_FILE_TRANSFER_REQUEST, + NMT_FILE_TRANSFER_RESPONSE, + NMT_FILE_TRANSFER_DATA, + NMT_FILE_TRANSFER_ACK, + + NMT_JOIN_SYNC_START, + + NMT_REJOINED, + NMT_KICKED, + + NMT_CLIENT_TIMEOUT, + NMT_CLIENT_PERFORMANCE, + NMT_CLIENTS_LOADING, + NMT_CLIENT_PAUSED, + + NMT_LOADED_GAME, + NMT_GAME_START, + NMT_END_COMMAND_BATCH, + + NMT_SYNC_CHECK, // OOS-detection hash checking + NMT_SYNC_ERROR, // OOS-detection error + + NMT_SIMULATION_COMMAND +}; + +#endif // NETMESSAGETYPE_H Index: source/network/NetMessages.h =================================================================== --- source/network/NetMessages.h +++ source/network/NetMessages.h @@ -15,70 +15,16 @@ * along with 0 A.D. If not, see . */ -/** - * @file - * The list of messages used by the network subsystem. - */ - #ifndef NETMESSAGES_H #define NETMESSAGES_H +#include "NetMessageBuffer.h" #include "ps/CStr.h" -#include "scriptinterface/ScriptVal.h" - -#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?' -#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!' -#define PS_PROTOCOL_VERSION 0x01010015 // Arbitrary protocol -#define PS_DEFAULT_PORT 0x5073 // 'P', 's' - -// Defines the list of message types. The order of the list must not change. -// The message types having a negative value are used internally and not sent -// over the network. The message types used for network communication have -// positive values. -enum NetMessageType -{ - NMT_CONNECT_COMPLETE = -256, - NMT_CONNECTION_LOST, - NMT_INVALID = 0, - - NMT_SERVER_HANDSHAKE, - NMT_CLIENT_HANDSHAKE, - NMT_SERVER_HANDSHAKE_RESPONSE, - - NMT_AUTHENTICATE, - NMT_AUTHENTICATE_RESULT, - - NMT_CHAT, - NMT_READY, - NMT_CLEAR_ALL_READY, - NMT_GAME_SETUP, - NMT_ASSIGN_PLAYER, - NMT_PLAYER_ASSIGNMENT, - - NMT_FILE_TRANSFER_REQUEST, - NMT_FILE_TRANSFER_RESPONSE, - NMT_FILE_TRANSFER_DATA, - NMT_FILE_TRANSFER_ACK, - - NMT_JOIN_SYNC_START, - - NMT_REJOINED, - NMT_KICKED, - NMT_CLIENT_TIMEOUT, - NMT_CLIENT_PERFORMANCE, - NMT_CLIENTS_LOADING, - NMT_CLIENT_PAUSED, - - NMT_LOADED_GAME, - NMT_GAME_START, - NMT_END_COMMAND_BATCH, - - NMT_SYNC_CHECK, // OOS-detection hash checking - NMT_SYNC_ERROR, // OOS-detection error - - NMT_SIMULATION_COMMAND -}; +#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?' +#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!' +#define PS_PROTOCOL_VERSION 0x01010016 // Arbitrary protocol +#define PS_DEFAULT_PORT 0x5073 // 'P', 's' // Authentication result codes enum AuthenticateResultCode @@ -88,164 +34,231 @@ ARC_PASSWORD_INVALID, }; -#endif // NETMESSAGES_H - -#ifdef CREATING_NMT - -#define ALLNETMSGS_DONT_CREATE_NMTS -#define START_NMT_CLASS_(_nm, _message) START_NMT_CLASS(C##_nm##Message, _message) -#define DERIVE_NMT_CLASS_(_base, _nm, _message) START_NMT_CLASS_DERIVED(C ## _base ## Message, C ## _nm ## Message, _message) - -START_NMTS() - -START_NMT_CLASS_(SrvHandshake, NMT_SERVER_HANDSHAKE) - NMT_FIELD_INT(m_Magic, u32, 4) - NMT_FIELD_INT(m_ProtocolVersion, u32, 4) - NMT_FIELD_INT(m_SoftwareVersion, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(CliHandshake, NMT_CLIENT_HANDSHAKE) - NMT_FIELD_INT(m_MagicResponse, u32, 4) - NMT_FIELD_INT(m_ProtocolVersion, u32, 4) - NMT_FIELD_INT(m_SoftwareVersion, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(SrvHandshakeResponse, NMT_SERVER_HANDSHAKE_RESPONSE) - NMT_FIELD_INT(m_UseProtocolVersion, u32, 4) - NMT_FIELD_INT(m_Flags, u32, 4) - NMT_FIELD(CStrW, m_Message) -END_NMT_CLASS() - -START_NMT_CLASS_(Authenticate, NMT_AUTHENTICATE) - NMT_FIELD(CStr, m_GUID) - NMT_FIELD(CStrW, m_Name) - NMT_FIELD(CStrW, m_Password) - NMT_FIELD_INT(m_IsLocalClient, u8, 1) -END_NMT_CLASS() - -START_NMT_CLASS_(AuthenticateResult, NMT_AUTHENTICATE_RESULT) - NMT_FIELD_INT(m_Code, u32, 4) - NMT_FIELD_INT(m_HostID, u32, 2) - NMT_FIELD(CStrW, m_Message) -END_NMT_CLASS() - -START_NMT_CLASS_(Chat, NMT_CHAT) - NMT_FIELD(CStr, m_GUID) // ignored when client->server, valid when server->client - NMT_FIELD(CStrW, m_Message) -END_NMT_CLASS() - -START_NMT_CLASS_(Ready, NMT_READY) - NMT_FIELD(CStr, m_GUID) - NMT_FIELD_INT(m_Status, u8, 1) -END_NMT_CLASS() - -START_NMT_CLASS_(ClearAllReady, NMT_CLEAR_ALL_READY) -END_NMT_CLASS() - -START_NMT_CLASS_(PlayerAssignment, NMT_PLAYER_ASSIGNMENT) - NMT_START_ARRAY(m_Hosts) - NMT_FIELD(CStr, m_GUID) - NMT_FIELD(CStrW, m_Name) - NMT_FIELD_INT(m_PlayerID, i8, 1) - NMT_FIELD_INT(m_Status, u8, 1) - NMT_END_ARRAY() -END_NMT_CLASS() - -START_NMT_CLASS_(FileTransferRequest, NMT_FILE_TRANSFER_REQUEST) - NMT_FIELD_INT(m_RequestID, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(FileTransferResponse, NMT_FILE_TRANSFER_RESPONSE) - NMT_FIELD_INT(m_RequestID, u32, 4) - NMT_FIELD_INT(m_Length, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(FileTransferData, NMT_FILE_TRANSFER_DATA) - NMT_FIELD_INT(m_RequestID, u32, 4) - NMT_FIELD(CStr, m_Data) -END_NMT_CLASS() - -START_NMT_CLASS_(FileTransferAck, NMT_FILE_TRANSFER_ACK) - NMT_FIELD_INT(m_RequestID, u32, 4) - NMT_FIELD_INT(m_NumPackets, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(JoinSyncStart, NMT_JOIN_SYNC_START) -END_NMT_CLASS() - -START_NMT_CLASS_(Rejoined, NMT_REJOINED) - NMT_FIELD(CStr, m_GUID) -END_NMT_CLASS() - -START_NMT_CLASS_(Kicked, NMT_KICKED) - NMT_FIELD(CStrW, m_Name) - NMT_FIELD_INT(m_Ban, u8, 1) -END_NMT_CLASS() - -START_NMT_CLASS_(ClientTimeout, NMT_CLIENT_TIMEOUT) - NMT_FIELD(CStr, m_GUID) - NMT_FIELD_INT(m_LastReceivedTime, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(ClientPerformance, NMT_CLIENT_PERFORMANCE) - NMT_START_ARRAY(m_Clients) - NMT_FIELD(CStr, m_GUID) - NMT_FIELD_INT(m_MeanRTT, u32, 4) - NMT_END_ARRAY() -END_NMT_CLASS() - -START_NMT_CLASS_(ClientsLoading, NMT_CLIENTS_LOADING) - NMT_START_ARRAY(m_Clients) - NMT_FIELD(CStr, m_GUID) - NMT_END_ARRAY() -END_NMT_CLASS() - -START_NMT_CLASS_(ClientPaused, NMT_CLIENT_PAUSED) - NMT_FIELD(CStr, m_GUID) - NMT_FIELD_INT(m_Pause, u8, 1) -END_NMT_CLASS() - -START_NMT_CLASS_(LoadedGame, NMT_LOADED_GAME) - NMT_FIELD_INT(m_CurrentTurn, u32, 4) -END_NMT_CLASS() - -START_NMT_CLASS_(GameStart, NMT_GAME_START) -END_NMT_CLASS() - -START_NMT_CLASS_(EndCommandBatch, NMT_END_COMMAND_BATCH) - NMT_FIELD_INT(m_Turn, u32, 4) - NMT_FIELD_INT(m_TurnLength, u32, 2) -END_NMT_CLASS() - -START_NMT_CLASS_(SyncCheck, NMT_SYNC_CHECK) - NMT_FIELD_INT(m_Turn, u32, 4) - NMT_FIELD(CStr, m_Hash) -END_NMT_CLASS() - -START_NMT_CLASS_(SyncError, NMT_SYNC_ERROR) - NMT_FIELD_INT(m_Turn, u32, 4) - NMT_FIELD(CStr, m_HashExpected) - NMT_START_ARRAY(m_PlayerNames) - NMT_FIELD(CStrW, m_Name) - NMT_END_ARRAY() -END_NMT_CLASS() - -START_NMT_CLASS_(AssignPlayer, NMT_ASSIGN_PLAYER) - NMT_FIELD_INT(m_PlayerID, i8, 1) - NMT_FIELD(CStr, m_GUID) -END_NMT_CLASS() - -END_NMTS() - -#else -#ifndef ALLNETMSGS_DONT_CREATE_NMTS - -# ifdef ALLNETMSGS_IMPLEMENT -# define NMT_CREATOR_IMPLEMENT -# endif - -# define NMT_CREATE_HEADER_NAME "NetMessages.h" -# include "NMTCreator.h" - -#endif // #ifndef ALLNETMSGS_DONT_CREATE_NMTS -#endif // #ifdef CREATING_NMT +/** + * Special message type for simulation commands. + * These commands are exposed as arbitrary JS objects, associated with a specific player. + */ +BEGIN_NETMESSAGE_WITH_CUSTOM_CONSTRUCTOR(CSimulationMessage, NMT_SIMULATION_COMMAND) + CSimulationMessage(ScriptInterface& scriptInterface) : + m_JSData(scriptInterface) + { + } + + CSimulationMessage(ScriptInterface& scriptInterface, u32 client, i32 player, u32 turn, JS::HandleValue data) : + m_Client(client), + m_Player(player), + m_Turn(turn), + m_JSData(scriptInterface, data) + { + } + + CSimulationMessage(ScriptInterface& scriptInterface, const CNetMessageBuffer& buffer) : + m_JSData(scriptInterface) + { + buffer.GetMessage(*this); + } + + u32 m_Client; + i32 m_Player; + u32 m_Turn; + SerializableJSValue m_JSData; + REGISTER_SERIALIZABLE(m_Client, m_Player, m_Turn, m_JSData) +END_NETMESSAGE_WITH_CUSTOM_CONSTRUCTOR() + +/** + * Special message type for updates to game settings. + */ +BEGIN_NETMESSAGE_WITH_CUSTOM_CONSTRUCTOR(CGameSetupMessage, NMT_GAME_SETUP) + NONCOPYABLE(CGameSetupMessage); +public: + CGameSetupMessage(ScriptInterface& scriptInterface) : + m_JSData(scriptInterface) + { + } + + CGameSetupMessage(ScriptInterface& scriptInterface, JS::HandleValue data) : + m_JSData(scriptInterface, data) + { + } + + CGameSetupMessage(ScriptInterface& scriptInterface, const CNetMessageBuffer& buffer) : + m_JSData(scriptInterface) + { + buffer.GetMessage(*this); + } + + SerializableJSValue m_JSData; + REGISTER_SERIALIZABLE(m_JSData) +END_NETMESSAGE_WITH_CUSTOM_CONSTRUCTOR() + +BEGIN_NETMESSAGE(CSrvHandshakeMessage, NMT_SERVER_HANDSHAKE) + u32 m_Magic; + u32 m_ProtocolVersion; + u32 m_SoftwareVersion; + REGISTER_SERIALIZABLE(m_Magic, m_ProtocolVersion, m_SoftwareVersion) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CCliHandshakeMessage, NMT_CLIENT_HANDSHAKE) + u32 m_MagicResponse; + u32 m_ProtocolVersion; + u32 m_SoftwareVersion; + REGISTER_SERIALIZABLE(m_MagicResponse, m_ProtocolVersion, m_SoftwareVersion) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CSrvHandshakeResponseMessage, NMT_SERVER_HANDSHAKE_RESPONSE) + u32 m_UseProtocolVersion; + u32 m_Flags; + CStrW m_Message; + REGISTER_SERIALIZABLE(m_UseProtocolVersion, m_Flags, m_Message) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CAuthenticateMessage, NMT_AUTHENTICATE) + CStr m_GUID; + CStrW m_Name; + CStrW m_Password; + u8 m_IsLocalClient; + REGISTER_SERIALIZABLE(m_GUID, m_Name, m_Password, m_IsLocalClient) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CAuthenticateResultMessage, NMT_AUTHENTICATE_RESULT) + u32 m_Code; + u16 m_HostID; + CStrW m_Message; + REGISTER_SERIALIZABLE(m_Code, m_HostID, m_Message) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CChatMessage, NMT_CHAT) + CStr m_GUID; // ignored when client->server, valid when server->client + CStrW m_Message; + REGISTER_SERIALIZABLE(m_GUID, m_Message) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CReadyMessage, NMT_READY) + CStr m_GUID; // ignored when client->server, valid when server->client + u8 m_Status; + REGISTER_SERIALIZABLE(m_GUID, m_Status) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CClearAllReadyMessage, NMT_CLEAR_ALL_READY) + REGISTER_SERIALIZABLE_EMPTY() +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CPlayerAssignmentMessage, NMT_PLAYER_ASSIGNMENT) + BEGIN_SERIALIZABLE(SHost) + CStr m_GUID; + CStrW m_Name; + i8 m_PlayerID; + u8 m_Status; + REGISTER_SERIALIZABLE(m_GUID, m_Name, m_PlayerID, m_Status) + END_SERIALIZABLE() + + std::vector m_Hosts; + REGISTER_SERIALIZABLE(m_Hosts) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CFileTransferRequestMessage, NMT_FILE_TRANSFER_REQUEST) + u32 m_RequestID; + REGISTER_SERIALIZABLE(m_RequestID) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CFileTransferResponseMessage, NMT_FILE_TRANSFER_RESPONSE) + u32 m_RequestID; + u32 m_Length; + REGISTER_SERIALIZABLE(m_RequestID, m_Length) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CFileTransferDataMessage, NMT_FILE_TRANSFER_DATA) + u32 m_RequestID; + CStr m_Data; + REGISTER_SERIALIZABLE(m_RequestID, m_Data) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CFileTransferAckMessage, NMT_FILE_TRANSFER_ACK) + u32 m_RequestID; + u32 m_NumPackets; + REGISTER_SERIALIZABLE(m_RequestID, m_NumPackets) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CJoinSyncStartMessage, NMT_JOIN_SYNC_START) + REGISTER_SERIALIZABLE_EMPTY() +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CRejoinedMessage, NMT_REJOINED) + CStr m_GUID; + REGISTER_SERIALIZABLE(m_GUID) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CKickedMessage, NMT_KICKED) + CStrW m_Name; + u8 m_Ban; + REGISTER_SERIALIZABLE(m_Name, m_Ban) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CClientTimeoutMessage, NMT_CLIENT_TIMEOUT) + CStr m_GUID; + u32 m_LastReceivedTime; + REGISTER_SERIALIZABLE(m_GUID, m_LastReceivedTime) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CClientPerformanceMessage, NMT_CLIENT_PERFORMANCE) + BEGIN_SERIALIZABLE(SClient) + CStr m_GUID; + u32 m_MeanRTT; + REGISTER_SERIALIZABLE(m_GUID, m_MeanRTT) + END_SERIALIZABLE() + + std::vector m_Clients; + REGISTER_SERIALIZABLE(m_Clients) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CClientsLoadingMessage, NMT_CLIENTS_LOADING) + BEGIN_SERIALIZABLE(SClient) + CStr m_GUID; + REGISTER_SERIALIZABLE(m_GUID) + END_SERIALIZABLE() + + std::vector m_Clients; + REGISTER_SERIALIZABLE(m_Clients) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CClientPausedMessage, NMT_CLIENT_PAUSED) + CStr m_GUID; + u8 m_Pause; + REGISTER_SERIALIZABLE(m_GUID, m_Pause) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CLoadedGameMessage, NMT_LOADED_GAME) + u32 m_CurrentTurn; + REGISTER_SERIALIZABLE(m_CurrentTurn) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CGameStartMessage, NMT_GAME_START) + REGISTER_SERIALIZABLE_EMPTY() +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CEndCommandBatchMessage, NMT_END_COMMAND_BATCH) + u32 m_Turn; + u16 m_TurnLength; + REGISTER_SERIALIZABLE(m_Turn, m_TurnLength) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CSyncCheckMessage, NMT_SYNC_CHECK) + u32 m_Turn; + CStr m_Hash; + REGISTER_SERIALIZABLE(m_Turn, m_Hash) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CSyncErrorMessage, NMT_SYNC_ERROR) + u32 m_Turn; + CStr m_HashExpected; + std::vector m_PlayerNames; + REGISTER_SERIALIZABLE(m_Turn, m_HashExpected, m_PlayerNames) +END_NETMESSAGE() + +BEGIN_NETMESSAGE(CAssignPlayerMessage, NMT_ASSIGN_PLAYER) + i8 m_PlayerID; + CStr m_GUID; + REGISTER_SERIALIZABLE(m_PlayerID, m_GUID) +END_NETMESSAGE() + +#endif // NETMESSAGES_H Index: source/network/NetServer.h =================================================================== --- source/network/NetServer.h +++ source/network/NetServer.h @@ -20,6 +20,7 @@ #include "NetFileTransfer.h" #include "NetHost.h" +#include "NetMessages.h" #include "lib/config2.h" #include "ps/ThreadUtil.h" @@ -33,8 +34,6 @@ class ScriptInterface; class CPlayerAssignmentMessage; class CNetStatsTable; -class CSimulationMessage; - class CNetServerWorker; enum NetServerState @@ -162,7 +161,7 @@ /** * Send a message to the given network peer. */ - bool SendMessage(ENetPeer* peer, const CNetMessage* message); + bool SendMessage(ENetPeer* peer, const CNetMessageBuffer& message); /** * Disconnects a player from gamesetup or session. @@ -172,7 +171,7 @@ /** * Send a message to all clients who match one of the given states. */ - bool Broadcast(const CNetMessage* message, const std::vector& targetStates); + bool Broadcast(const CNetMessageBuffer& message, const std::vector& targetStates); private: friend class CNetServer; @@ -240,21 +239,21 @@ void OnUserJoin(CNetServerSession* session); void OnUserLeave(CNetServerSession* session); - static bool OnClientHandshake(void* context, CFsmEvent* event); - static bool OnAuthenticate(void* context, CFsmEvent* event); - static bool OnInGame(void* context, CFsmEvent* event); - static bool OnChat(void* context, CFsmEvent* event); - static bool OnReady(void* context, CFsmEvent* event); - static bool OnClearAllReady(void* context, CFsmEvent* event); - static bool OnGameSetup(void* context, CFsmEvent* event); - static bool OnAssignPlayer(void* context, CFsmEvent* event); - static bool OnStartGame(void* context, CFsmEvent* event); - static bool OnLoadedGame(void* context, CFsmEvent* event); - static bool OnJoinSyncingLoadedGame(void* context, CFsmEvent* event); - static bool OnRejoined(void* context, CFsmEvent* event); - static bool OnKickPlayer(void* context, CFsmEvent* event); - static bool OnDisconnect(void* context, CFsmEvent* event); - static bool OnClientPaused(void* context, CFsmEvent* event); + static bool OnClientHandshake(void* context, const CFsmEvent& event); + static bool OnAuthenticate(void* context, const CFsmEvent& event); + static bool OnInGame(void* context, const CFsmEvent& event); + static bool OnChat(void* context, const CFsmEvent& event); + static bool OnReady(void* context, const CFsmEvent& event); + static bool OnClearAllReady(void* context, const CFsmEvent& event); + static bool OnGameSetup(void* context, const CFsmEvent& event); + static bool OnAssignPlayer(void* context, const CFsmEvent& event); + static bool OnStartGame(void* context, const CFsmEvent& event); + static bool OnLoadedGame(void* context, const CFsmEvent& event); + static bool OnJoinSyncingLoadedGame(void* context, const CFsmEvent& event); + static bool OnRejoined(void* context, const CFsmEvent& event); + static bool OnKickPlayer(void* context, const CFsmEvent& event); + static bool OnDisconnect(void* context, const CFsmEvent& event); + static bool OnClientPaused(void* context, const CFsmEvent& event); /** * Checks if all clients have finished loading. @@ -266,7 +265,7 @@ void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message); - void HandleMessageReceive(const CNetMessage* message, CNetServerSession* session); + void HandleMessageReceive(const CNetMessageBuffer& message, CNetServerSession* session); /** * Send a network warning if the connection to a client is being lost or has bad latency. Index: source/network/NetServer.cpp =================================================================== --- source/network/NetServer.cpp +++ source/network/NetServer.cpp @@ -20,7 +20,6 @@ #include "NetServer.h" #include "NetClient.h" -#include "NetMessage.h" #include "NetSession.h" #include "NetServerTurnManager.h" #include "NetStats.h" @@ -114,7 +113,7 @@ // which should still work but isn't great m_Server.m_JoinSyncFile = m_Buffer; CJoinSyncStartMessage message; - session->SendMessage(&message); + session->SendMessage(message); } private: @@ -331,7 +330,7 @@ } #endif // CONFIG2_MINIUPNPC -bool CNetServerWorker::SendMessage(ENetPeer* peer, const CNetMessage* message) +bool CNetServerWorker::SendMessage(ENetPeer* peer, const CNetMessageBuffer& message) { ENSURE(m_Host); @@ -340,7 +339,7 @@ return CNetHost::SendMessage(message, peer, DebugName(session).c_str()); } -bool CNetServerWorker::Broadcast(const CNetMessage* message, const std::vector& targetStates) +bool CNetServerWorker::Broadcast(const CNetMessageBuffer& message, const std::vector& targetStates) { ENSURE(m_Host); @@ -518,15 +517,8 @@ if (session) { // Create message from raw data - CNetMessage* msg = CNetMessageFactory::CreateMessage(event.packet->data, event.packet->dataLength, GetScriptInterface()); - if (msg) - { - LOGMESSAGE("Net server: Received message %s of size %lu from %s", msg->ToString().c_str(), (unsigned long)msg->GetSerializedLength(), DebugName(session).c_str()); - - HandleMessageReceive(msg, session); - - delete msg; - } + CNetMessageBuffer msg(event.packet->data, event.packet->dataLength); + HandleMessageReceive(msg, session); } // Done using the packet @@ -559,24 +551,24 @@ u32 lastReceived = m_Sessions[i]->GetLastReceivedTime(); u32 meanRTT = m_Sessions[i]->GetMeanRTT(); - CNetMessage* message = nullptr; + CNetMessageBuffer message; // Report if we didn't hear from the client since few seconds if (lastReceived > NETWORK_WARNING_TIMEOUT) { - CClientTimeoutMessage* msg = new CClientTimeoutMessage(); - msg->m_GUID = m_Sessions[i]->GetGUID(); - msg->m_LastReceivedTime = lastReceived; + CClientTimeoutMessage msg; + msg.m_GUID = m_Sessions[i]->GetGUID(); + msg.m_LastReceivedTime = lastReceived; message = msg; } // Report if the client has bad ping else if (meanRTT > DEFAULT_TURN_LENGTH_MP) { - CClientPerformanceMessage* msg = new CClientPerformanceMessage(); - CClientPerformanceMessage::S_m_Clients client; - client.m_GUID = m_Sessions[i]->GetGUID(); + CClientPerformanceMessage::SClient client; client.m_MeanRTT = meanRTT; - msg->m_Clients.push_back(client); + client.m_GUID = m_Sessions[i]->GetGUID(); + CClientPerformanceMessage msg; + msg.m_Clients.push_back(client); message = msg; } @@ -592,34 +584,32 @@ m_Sessions[j]->SendMessage(message); } } - - SAFE_DELETE(message); } } -void CNetServerWorker::HandleMessageReceive(const CNetMessage* message, CNetServerSession* session) +void CNetServerWorker::HandleMessageReceive(const CNetMessageBuffer& message, CNetServerSession* session) { // Handle non-FSM messages first Status status = session->GetFileTransferer().HandleMessageReceive(message); if (status != INFO::SKIPPED) return; - if (message->GetType() == NMT_FILE_TRANSFER_REQUEST) + if (message.GetType() == NMT_FILE_TRANSFER_REQUEST) { - CFileTransferRequestMessage* reqMessage = (CFileTransferRequestMessage*)message; + CFileTransferRequestMessage reqMessage(message); // Rejoining client got our JoinSyncStart after we received the state from // another client, and has now requested that we forward it to them ENSURE(!m_JoinSyncFile.empty()); - session->GetFileTransferer().StartResponse(reqMessage->m_RequestID, m_JoinSyncFile); + session->GetFileTransferer().StartResponse(reqMessage.m_RequestID, m_JoinSyncFile); return; } // Update FSM - if (!session->Update(message->GetType(), (void*)message)) - LOGERROR("Net server: Error running FSM update (type=%d state=%d)", (int)message->GetType(), (int)session->GetCurrState()); + if (!session->Update(message.GetType(), &message)) + LOGERROR("Net server: Error running FSM update (type=%d state=%d)", (int)message.GetType(), (int)session->GetCurrState()); } void CNetServerWorker::SetupSession(CNetServerSession* session) @@ -631,36 +621,33 @@ session->AddTransition(NSS_UNCONNECTED, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED); session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED); - session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CLIENT_HANDSHAKE, NSS_AUTHENTICATE, (void*)&OnClientHandshake, context); + session->AddTransition(NSS_HANDSHAKE, (uint)NMT_CLIENT_HANDSHAKE, NSS_AUTHENTICATE, &OnClientHandshake, context); session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED); - session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_AUTHENTICATE, NSS_PREGAME, (void*)&OnAuthenticate, context); - - session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, (void*)&OnChat, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, (void*)&OnReady, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_CLEAR_ALL_READY, NSS_PREGAME, (void*)&OnClearAllReady, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_GAME_SETUP, NSS_PREGAME, (void*)&OnGameSetup, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_ASSIGN_PLAYER, NSS_PREGAME, (void*)&OnAssignPlayer, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_KICKED, NSS_PREGAME, (void*)&OnKickPlayer, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_GAME_START, NSS_PREGAME, (void*)&OnStartGame, context); - session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnLoadedGame, context); - - session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_KICKED, NSS_JOIN_SYNCING, (void*)&OnKickPlayer, context); - session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); - session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, (void*)&OnJoinSyncingLoadedGame, context); - - session->AddTransition(NSS_INGAME, (uint)NMT_REJOINED, NSS_INGAME, (void*)&OnRejoined, context); - session->AddTransition(NSS_INGAME, (uint)NMT_KICKED, NSS_INGAME, (void*)&OnKickPlayer, context); - session->AddTransition(NSS_INGAME, (uint)NMT_CLIENT_PAUSED, NSS_INGAME, (void*)&OnClientPaused, context); - session->AddTransition(NSS_INGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, (void*)&OnDisconnect, context); - session->AddTransition(NSS_INGAME, (uint)NMT_CHAT, NSS_INGAME, (void*)&OnChat, context); - session->AddTransition(NSS_INGAME, (uint)NMT_SIMULATION_COMMAND, NSS_INGAME, (void*)&OnInGame, context); - session->AddTransition(NSS_INGAME, (uint)NMT_SYNC_CHECK, NSS_INGAME, (void*)&OnInGame, context); - session->AddTransition(NSS_INGAME, (uint)NMT_END_COMMAND_BATCH, NSS_INGAME, (void*)&OnInGame, context); - - // Set first state - session->SetFirstState(NSS_HANDSHAKE); + session->AddTransition(NSS_AUTHENTICATE, (uint)NMT_AUTHENTICATE, NSS_PREGAME, &OnAuthenticate, context); + + session->AddTransition(NSS_PREGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, &OnDisconnect, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_CHAT, NSS_PREGAME, &OnChat, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_READY, NSS_PREGAME, &OnReady, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_CLEAR_ALL_READY, NSS_PREGAME, &OnClearAllReady, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_GAME_SETUP, NSS_PREGAME, &OnGameSetup, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_ASSIGN_PLAYER, NSS_PREGAME, &OnAssignPlayer, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_KICKED, NSS_PREGAME, &OnKickPlayer, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_GAME_START, NSS_PREGAME, &OnStartGame, context); + session->AddTransition(NSS_PREGAME, (uint)NMT_LOADED_GAME, NSS_INGAME, &OnLoadedGame, context); + + session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_KICKED, NSS_JOIN_SYNCING, &OnKickPlayer, context); + session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, &OnDisconnect, context); + session->AddTransition(NSS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NSS_INGAME, &OnJoinSyncingLoadedGame, context); + + session->AddTransition(NSS_INGAME, (uint)NMT_REJOINED, NSS_INGAME, &OnRejoined, context); + session->AddTransition(NSS_INGAME, (uint)NMT_KICKED, NSS_INGAME, &OnKickPlayer, context); + session->AddTransition(NSS_INGAME, (uint)NMT_CLIENT_PAUSED, NSS_INGAME, &OnClientPaused, context); + session->AddTransition(NSS_INGAME, (uint)NMT_CONNECTION_LOST, NSS_UNCONNECTED, &OnDisconnect, context); + session->AddTransition(NSS_INGAME, (uint)NMT_CHAT, NSS_INGAME, &OnChat, context); + session->AddTransition(NSS_INGAME, (uint)NMT_SIMULATION_COMMAND, NSS_INGAME, &OnInGame, context); + session->AddTransition(NSS_INGAME, (uint)NMT_SYNC_CHECK, NSS_INGAME, &OnInGame, context); + session->AddTransition(NSS_INGAME, (uint)NMT_END_COMMAND_BATCH, NSS_INGAME, &OnInGame, context); } bool CNetServerWorker::HandleConnect(CNetServerSession* session) @@ -675,7 +662,7 @@ handshake.m_Magic = PS_PROTOCOL_MAGIC; handshake.m_ProtocolVersion = PS_PROTOCOL_VERSION; handshake.m_SoftwareVersion = PS_PROTOCOL_VERSION; - return session->SendMessage(&handshake); + return session->SendMessage(CNetMessageBuffer(handshake)); } void CNetServerWorker::OnUserJoin(CNetServerSession* session) @@ -685,13 +672,12 @@ if (m_HostGUID.empty() && session->IsLocalClient()) m_HostGUID = session->GetGUID(); - CGameSetupMessage gameSetupMessage(GetScriptInterface()); - gameSetupMessage.m_Data = m_GameAttributes; - session->SendMessage(&gameSetupMessage); + CGameSetupMessage gameSetupMessage(GetScriptInterface(), (JS::HandleValue)m_GameAttributes); + session->SendMessage(CNetMessageBuffer(gameSetupMessage)); CPlayerAssignmentMessage assignMessage; ConstructPlayerAssignmentMessage(assignMessage); - session->SendMessage(&assignMessage); + session->SendMessage(assignMessage); } void CNetServerWorker::OnUserLeave(CNetServerSession* session) @@ -804,7 +790,7 @@ CKickedMessage kickedMessage; kickedMessage.m_Name = playerName; kickedMessage.m_Ban = ban; - Broadcast(&kickedMessage, { NSS_PREGAME, NSS_JOIN_SYNCING, NSS_INGAME }); + Broadcast(kickedMessage, { NSS_PREGAME, NSS_JOIN_SYNCING, NSS_INGAME }); } void CNetServerWorker::AssignPlayer(int playerID, const CStr& guid) @@ -830,7 +816,7 @@ if (!p.second.m_Enabled) continue; - CPlayerAssignmentMessage::S_m_Hosts h; + CPlayerAssignmentMessage::SHost h; h.m_GUID = p.first; h.m_Name = p.second.m_Name; h.m_PlayerID = p.second.m_PlayerID; @@ -843,7 +829,7 @@ { CPlayerAssignmentMessage message; ConstructPlayerAssignmentMessage(message); - Broadcast(&message, { NSS_PREGAME, NSS_JOIN_SYNCING, NSS_INGAME }); + Broadcast(message, { NSS_PREGAME, NSS_JOIN_SYNCING, NSS_INGAME }); } ScriptInterface& CNetServerWorker::GetScriptInterface() @@ -857,15 +843,15 @@ m_ServerTurnManager->SetTurnLength(msecs); } -bool CNetServerWorker::OnClientHandshake(void* context, CFsmEvent* event) +bool CNetServerWorker::OnClientHandshake(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CLIENT_HANDSHAKE); + ENSURE(event.GetType() == (uint)NMT_CLIENT_HANDSHAKE); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); - CCliHandshakeMessage* message = (CCliHandshakeMessage*)event->GetParamRef(); - if (message->m_ProtocolVersion != PS_PROTOCOL_VERSION) + CCliHandshakeMessage message(event.GetMessageBuffer()); + if (message.m_ProtocolVersion != PS_PROTOCOL_VERSION) { session->Disconnect(NDR_INCORRECT_PROTOCOL_VERSION); return false; @@ -875,14 +861,14 @@ handshakeResponse.m_UseProtocolVersion = PS_PROTOCOL_VERSION; handshakeResponse.m_Message = server.m_WelcomeMessage; handshakeResponse.m_Flags = 0; - session->SendMessage(&handshakeResponse); + session->SendMessage(handshakeResponse); return true; } -bool CNetServerWorker::OnAuthenticate(void* context, CFsmEvent* event) +bool CNetServerWorker::OnAuthenticate(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_AUTHENTICATE); + ENSURE(event.GetType() == (uint)NMT_AUTHENTICATE); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); @@ -895,9 +881,9 @@ return true; } - CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef(); - CStrW username = SanitisePlayerName(message->m_Name); - CStr guid = message->m_GUID; + CAuthenticateMessage message(event.GetMessageBuffer()); + CStrW username = SanitisePlayerName(message.m_Name); + CStr guid = message.m_GUID; // Either deduplicate or prohibit join if name is in use bool duplicatePlayernames = false; @@ -1018,15 +1004,15 @@ u32 newHostID = server.m_NextHostID++; session->SetUserName(username); - session->SetGUID(message->m_GUID); + session->SetGUID(message.m_GUID); session->SetHostID(newHostID); - session->SetLocalClient(message->m_IsLocalClient); + session->SetLocalClient(message.m_IsLocalClient); CAuthenticateResultMessage authenticateResult; authenticateResult.m_Code = isRejoining ? ARC_OK_REJOINING : ARC_OK; authenticateResult.m_HostID = newHostID; authenticateResult.m_Message = L"Logged in"; - session->SendMessage(&authenticateResult); + session->SendMessage(authenticateResult); server.OnUserJoin(session); @@ -1048,17 +1034,19 @@ return true; } -bool CNetServerWorker::OnInGame(void* context, CFsmEvent* event) +bool CNetServerWorker::OnInGame(void* context, const CFsmEvent& event) { // TODO: should split each of these cases into a separate method CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); - CNetMessage* message = (CNetMessage*)event->GetParamRef(); - if (message->GetType() == (uint)NMT_SIMULATION_COMMAND) + const CNetMessageBuffer& message = event.GetMessageBuffer(); + switch (message.GetType()) + { + case NMT_SIMULATION_COMMAND: { - CSimulationMessage* simMessage = static_cast (message); + CSimulationMessage simMessage(server.GetScriptInterface(), message); // Ignore messages sent by one player on behalf of another player // unless cheating is enabled @@ -1074,54 +1062,58 @@ PlayerAssignmentMap::iterator it = server.m_PlayerAssignments.find(session->GetGUID()); // When cheating is disabled, fail if the player the message claims to // represent does not exist or does not match the sender's player name - if (!cheatsEnabled && (it == server.m_PlayerAssignments.end() || it->second.m_PlayerID != simMessage->m_Player)) + if (!cheatsEnabled && (it == server.m_PlayerAssignments.end() || it->second.m_PlayerID != simMessage.m_Player)) return true; // Send it back to all clients that have finished // the loading screen (and the synchronization when rejoining) - server.Broadcast(simMessage, { NSS_INGAME }); + server.Broadcast(message, { NSS_INGAME }); // Save all the received commands - if (server.m_SavedCommands.size() < simMessage->m_Turn + 1) - server.m_SavedCommands.resize(simMessage->m_Turn + 1); - server.m_SavedCommands[simMessage->m_Turn].push_back(*simMessage); + if (server.m_SavedCommands.size() < simMessage.m_Turn + 1) + server.m_SavedCommands.resize(simMessage.m_Turn + 1); + server.m_SavedCommands[simMessage.m_Turn].push_back(simMessage); // TODO: we shouldn't send the message back to the client that first sent it + break; } - else if (message->GetType() == (uint)NMT_SYNC_CHECK) + case NMT_SYNC_CHECK: { - CSyncCheckMessage* syncMessage = static_cast (message); - server.m_ServerTurnManager->NotifyFinishedClientUpdate(session->GetHostID(), session->GetUserName(), syncMessage->m_Turn, syncMessage->m_Hash); + CSyncCheckMessage syncMessage(message); + server.m_ServerTurnManager->NotifyFinishedClientUpdate(session->GetHostID(), session->GetUserName(), syncMessage.m_Turn, syncMessage.m_Hash); + break; } - else if (message->GetType() == (uint)NMT_END_COMMAND_BATCH) + case NMT_END_COMMAND_BATCH: { // The turn-length field is ignored - CEndCommandBatchMessage* endMessage = static_cast (message); - server.m_ServerTurnManager->NotifyFinishedClientCommands(session->GetHostID(), endMessage->m_Turn); + CEndCommandBatchMessage endMessage(message); + server.m_ServerTurnManager->NotifyFinishedClientCommands(session->GetHostID(), endMessage.m_Turn); + break; + } } return true; } -bool CNetServerWorker::OnChat(void* context, CFsmEvent* event) +bool CNetServerWorker::OnChat(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CHAT); + ENSURE(event.GetType() == (uint)NMT_CHAT); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); - CChatMessage* message = (CChatMessage*)event->GetParamRef(); + CChatMessage message(event.GetMessageBuffer()); - message->m_GUID = session->GetGUID(); + message.m_GUID = session->GetGUID(); server.Broadcast(message, { NSS_PREGAME, NSS_INGAME }); return true; } -bool CNetServerWorker::OnReady(void* context, CFsmEvent* event) +bool CNetServerWorker::OnReady(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_READY); + ENSURE(event.GetType() == (uint)NMT_READY); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); @@ -1131,18 +1123,18 @@ if (server.m_State == SERVER_STATE_LOADING) return true; - CReadyMessage* message = (CReadyMessage*)event->GetParamRef(); - message->m_GUID = session->GetGUID(); + CReadyMessage message(event.GetMessageBuffer()); + message.m_GUID = session->GetGUID(); server.Broadcast(message, { NSS_PREGAME }); - server.m_PlayerAssignments[message->m_GUID].m_Status = message->m_Status; + server.m_PlayerAssignments[message.m_GUID].m_Status = message.m_Status; return true; } -bool CNetServerWorker::OnClearAllReady(void* context, CFsmEvent* event) +bool CNetServerWorker::OnClearAllReady(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CLEAR_ALL_READY); + ENSURE(event.GetType() == (uint)NMT_CLEAR_ALL_READY); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); @@ -1153,38 +1145,38 @@ return true; } -bool CNetServerWorker::OnGameSetup(void* context, CFsmEvent* event) +bool CNetServerWorker::OnGameSetup(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_GAME_SETUP); + ENSURE(event.GetType() == (uint)NMT_GAME_SETUP); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); if (session->GetGUID() == server.m_HostGUID) { - CGameSetupMessage* message = (CGameSetupMessage*)event->GetParamRef(); - server.UpdateGameAttributes(&(message->m_Data)); + CGameSetupMessage message(server.GetScriptInterface(), event.GetMessageBuffer()); + server.UpdateGameAttributes(&message.m_JSData.m_Data); } return true; } -bool CNetServerWorker::OnAssignPlayer(void* context, CFsmEvent* event) +bool CNetServerWorker::OnAssignPlayer(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_ASSIGN_PLAYER); + ENSURE(event.GetType() == (uint)NMT_ASSIGN_PLAYER); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); if (session->GetGUID() == server.m_HostGUID) { - CAssignPlayerMessage* message = (CAssignPlayerMessage*)event->GetParamRef(); - server.AssignPlayer(message->m_PlayerID, message->m_GUID); + CAssignPlayerMessage message(event.GetMessageBuffer()); + server.AssignPlayer(message.m_PlayerID, message.m_GUID); } return true; } -bool CNetServerWorker::OnStartGame(void* context, CFsmEvent* event) +bool CNetServerWorker::OnStartGame(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_GAME_START); + ENSURE(event.GetType() == (uint)NMT_GAME_START); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); @@ -1194,9 +1186,9 @@ return true; } -bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event) +bool CNetServerWorker::OnLoadedGame(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); + ENSURE(event.GetType() == (uint)NMT_LOADED_GAME); CNetServerSession* loadedSession = (CNetServerSession*)context; CNetServerWorker& server = loadedSession->GetServer(); @@ -1213,19 +1205,19 @@ for (CNetServerSession* session : server.m_Sessions) if (session->GetCurrState() != NSS_INGAME && loadedSession->GetGUID() != session->GetGUID()) { - CClientsLoadingMessage::S_m_Clients client; + CClientsLoadingMessage::SClient client; client.m_GUID = session->GetGUID(); message.m_Clients.push_back(client); } // Send to the client who has loaded the game but did not reach the NSS_INGAME state yet - loadedSession->SendMessage(&message); - server.Broadcast(&message, { NSS_INGAME }); + loadedSession->SendMessage(CNetMessageBuffer(message)); + server.Broadcast(message, { NSS_INGAME }); return true; } -bool CNetServerWorker::OnJoinSyncingLoadedGame(void* context, CFsmEvent* event) +bool CNetServerWorker::OnJoinSyncingLoadedGame(void* context, const CFsmEvent& event) { // A client rejoining an in-progress game has now finished loading the // map and deserialized the initial state. @@ -1238,14 +1230,14 @@ // we could try repeating this process a few times until the client converges // on the up-to-date state, before setting them as active.) - ENSURE(event->GetType() == (uint)NMT_LOADED_GAME); + ENSURE(event.GetType() == (uint)NMT_LOADED_GAME); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); - CLoadedGameMessage* message = (CLoadedGameMessage*)event->GetParamRef(); + CLoadedGameMessage message(event.GetMessageBuffer()); - u32 turn = message->m_CurrentTurn; + u32 turn = message.m_CurrentTurn; u32 readyTurn = server.m_ServerTurnManager->GetReadyTurn(); // Send them all commands received since their saved state, @@ -1254,14 +1246,14 @@ { if (i < server.m_SavedCommands.size()) for (size_t j = 0; j < server.m_SavedCommands[i].size(); ++j) - session->SendMessage(&server.m_SavedCommands[i][j]); + session->SendMessage(server.m_SavedCommands[i][j]); if (i <= readyTurn) { CEndCommandBatchMessage endMessage; endMessage.m_Turn = i; endMessage.m_TurnLength = server.m_ServerTurnManager->GetSavedTurnLength(i); - session->SendMessage(&endMessage); + session->SendMessage(endMessage); } } @@ -1271,22 +1263,22 @@ // Tell the client that everything has finished loading and it should start now CLoadedGameMessage loaded; loaded.m_CurrentTurn = readyTurn; - session->SendMessage(&loaded); + session->SendMessage(loaded); return true; } -bool CNetServerWorker::OnRejoined(void* context, CFsmEvent* event) +bool CNetServerWorker::OnRejoined(void* context, const CFsmEvent& event) { // A client has finished rejoining and the loading screen disappeared. - ENSURE(event->GetType() == (uint)NMT_REJOINED); + ENSURE(event.GetType() == (uint)NMT_REJOINED); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); // Inform everyone of the client having rejoined - CRejoinedMessage* message = (CRejoinedMessage*)event->GetParamRef(); - message->m_GUID = session->GetGUID(); + CRejoinedMessage message(event.GetMessageBuffer()); + message.m_GUID = session->GetGUID(); server.Broadcast(message, { NSS_INGAME }); // Send all pausing players to the rejoined client. @@ -1295,30 +1287,30 @@ CClientPausedMessage pausedMessage; pausedMessage.m_GUID = guid; pausedMessage.m_Pause = true; - session->SendMessage(&pausedMessage); + session->SendMessage(pausedMessage); } return true; } -bool CNetServerWorker::OnKickPlayer(void* context, CFsmEvent* event) +bool CNetServerWorker::OnKickPlayer(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_KICKED); + ENSURE(event.GetType() == (uint)NMT_KICKED); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); if (session->GetGUID() == server.m_HostGUID) { - CKickedMessage* message = (CKickedMessage*)event->GetParamRef(); - server.KickPlayer(message->m_Name, message->m_Ban); + CKickedMessage message(event.GetMessageBuffer()); + server.KickPlayer(message.m_Name, message.m_Ban); } return true; } -bool CNetServerWorker::OnDisconnect(void* context, CFsmEvent* event) +bool CNetServerWorker::OnDisconnect(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CONNECTION_LOST); + ENSURE(event.GetType() == (uint)NMT_CONNECTION_LOST); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); @@ -1328,21 +1320,21 @@ return true; } -bool CNetServerWorker::OnClientPaused(void* context, CFsmEvent* event) +bool CNetServerWorker::OnClientPaused(void* context, const CFsmEvent& event) { - ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED); + ENSURE(event.GetType() == (uint)NMT_CLIENT_PAUSED); CNetServerSession* session = (CNetServerSession*)context; CNetServerWorker& server = session->GetServer(); - CClientPausedMessage* message = (CClientPausedMessage*)event->GetParamRef(); + CClientPausedMessage message(event.GetMessageBuffer()); - message->m_GUID = session->GetGUID(); + message.m_GUID = session->GetGUID(); // Update the list of pausing players. std::vector::iterator player = std::find(server.m_PausingPlayers.begin(), server.m_PausingPlayers.end(), session->GetGUID()); - if (message->m_Pause) + if (message.m_Pause) { if (player != server.m_PausingPlayers.end()) return true; @@ -1360,7 +1352,7 @@ // Send messages to clients that are in game, and are not the client who paused. for (CNetServerSession* session : server.m_Sessions) { - if (session->GetCurrState() == NSS_INGAME && message->m_GUID != session->GetGUID()) + if (session->GetCurrState() == NSS_INGAME && message.m_GUID != session->GetGUID()) session->SendMessage(message); } @@ -1378,7 +1370,7 @@ loaded.m_CurrentTurn = 0; // Notice the changedSession is still in the NSS_PREGAME state - Broadcast(&loaded, { NSS_PREGAME, NSS_INGAME }); + Broadcast(loaded, { NSS_PREGAME, NSS_INGAME }); m_State = SERVER_STATE_INGAME; return true; @@ -1406,7 +1398,7 @@ SendPlayerAssignments(); CGameStartMessage gameStart; - Broadcast(&gameStart, { NSS_PREGAME }); + Broadcast(gameStart, { NSS_PREGAME }); } void CNetServerWorker::UpdateGameAttributes(JS::MutableHandleValue attrs) @@ -1417,8 +1409,8 @@ return; CGameSetupMessage gameSetupMessage(GetScriptInterface()); - gameSetupMessage.m_Data = m_GameAttributes; - Broadcast(&gameSetupMessage, { NSS_PREGAME }); + gameSetupMessage.m_JSData.m_Data = m_GameAttributes; + Broadcast(gameSetupMessage, { NSS_PREGAME }); } CStrW CNetServerWorker::SanitisePlayerName(const CStrW& original) Index: source/network/NetServerTurnManager.cpp =================================================================== --- source/network/NetServerTurnManager.cpp +++ source/network/NetServerTurnManager.cpp @@ -17,7 +17,6 @@ #include "precompiled.h" -#include "NetMessage.h" #include "NetServerTurnManager.h" #include "NetServer.h" @@ -71,7 +70,7 @@ CEndCommandBatchMessage msg; msg.m_TurnLength = m_TurnLength; msg.m_Turn = m_ReadyTurn; - m_NetServer.Broadcast(&msg, { NSS_INGAME }); + m_NetServer.Broadcast(msg, { NSS_INGAME }); ENSURE(m_SavedTurnLengths.size() == m_ReadyTurn); m_SavedTurnLengths.push_back(m_TurnLength); @@ -126,11 +125,9 @@ msg.m_HashExpected = expected; for (const CStrW& playername : OOSPlayerNames) { - CSyncErrorMessage::S_m_PlayerNames h; - h.m_Name = playername; - msg.m_PlayerNames.push_back(h); + msg.m_PlayerNames.push_back(playername); } - m_NetServer.Broadcast(&msg, { NSS_INGAME }); + m_NetServer.Broadcast(msg, { NSS_INGAME }); break; } } Index: source/network/NetSession.h =================================================================== --- source/network/NetSession.h +++ source/network/NetSession.h @@ -18,7 +18,7 @@ #ifndef NETSESSION_H #define NETSESSION_H -#include "network/fsm.h" +#include "network/Fsm.h" #include "network/NetFileTransfer.h" #include "network/NetHost.h" #include "ps/CStr.h" @@ -57,7 +57,7 @@ { public: virtual ~INetSession() {} - virtual bool SendMessage(const CNetMessage* message) = 0; + virtual bool SendMessage(const CNetMessageBuffer& message) = 0; }; /** @@ -93,7 +93,7 @@ /** * Send a message to the server. */ - virtual bool SendMessage(const CNetMessage* message); + virtual bool SendMessage(const CNetMessageBuffer& message); /** * Number of milliseconds since the most recent packet of the server was received. @@ -184,7 +184,7 @@ /** * Send a message to the client. */ - virtual bool SendMessage(const CNetMessage* message); + virtual bool SendMessage(const CNetMessageBuffer& message); CNetFileTransferer& GetFileTransferer() { return m_FileTransferer; } Index: source/network/NetSession.cpp =================================================================== --- source/network/NetSession.cpp +++ source/network/NetSession.cpp @@ -19,7 +19,6 @@ #include "NetSession.h" #include "NetClient.h" #include "NetServer.h" -#include "NetMessage.h" #include "NetStats.h" #include "lib/external_libraries/enet.h" #include "ps/CLogger.h" @@ -146,14 +145,11 @@ case ENET_EVENT_TYPE_RECEIVE: { - CNetMessage* msg = CNetMessageFactory::CreateMessage(event.packet->data, event.packet->dataLength, m_Client.GetScriptInterface()); + CNetMessageBuffer msg(event.packet->data, event.packet->dataLength); + if (msg) { - LOGMESSAGE("Net client: Received message %s of size %lu from server", msg->ToString().c_str(), (unsigned long)msg->GetSerializedLength()); - m_Client.HandleMessage(msg); - - delete msg; } enet_packet_destroy(event.packet); @@ -177,7 +173,7 @@ enet_host_flush(m_Host); } -bool CNetClientSession::SendMessage(const CNetMessage* message) +bool CNetClientSession::SendMessage(const CNetMessageBuffer& message) { ENSURE(m_Host && m_Server); @@ -203,7 +199,7 @@ CNetServerSession::CNetServerSession(CNetServerWorker& server, ENetPeer* peer) : - m_Server(server), m_FileTransferer(this), m_Peer(peer) + CFsm(NSS_HANDSHAKE), m_Server(server), m_FileTransferer(this), m_Peer(peer) { } @@ -230,7 +226,7 @@ void CNetServerSession::Disconnect(u32 reason) { - Update((uint)NMT_CONNECTION_LOST, NULL); + Update(NMT_CONNECTION_LOST, nullptr); enet_peer_disconnect(m_Peer, reason); } @@ -240,7 +236,7 @@ enet_peer_disconnect_now(m_Peer, reason); } -bool CNetServerSession::SendMessage(const CNetMessage* message) +bool CNetServerSession::SendMessage(const CNetMessageBuffer& message) { return m_Server.SendMessage(m_Peer, message); } Index: source/network/Serialization.h =================================================================== --- source/network/Serialization.h +++ /dev/null @@ -1,105 +0,0 @@ -/* Copyright (C) 2015 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#ifndef INCLUDED_NETWORK_SERIALIZATION -#define INCLUDED_NETWORK_SERIALIZATION - -#define Serialize_int_1(_pos, _val) \ - STMT( *((_pos)++) = (u8)((_val)&0xff); ) - -#define Serialize_int_2(_pos, _val) STMT(\ - Serialize_int_1(_pos, (_val)>>8); \ - Serialize_int_1(_pos, (_val)); \ -) - -#define Serialize_int_3(_pos, _val) STMT(\ - Serialize_int_1(_pos, (_val)>>16); \ - Serialize_int_2(_pos, (_val)); \ -) - -#define Serialize_int_4(_pos, _val) STMT(\ - Serialize_int_1(_pos, (_val)>>24); \ - Serialize_int_3(_pos, (_val)); \ -) - -#define Serialize_int_8(_pos, _val) STMT(\ - Serialize_int_4(_pos, (_val)>>32); \ - Serialize_int_4(_pos, (_val)); \ -) - -#define __shift_de(_pos, _val) STMT( \ - (_val) <<= 8; \ - (_val) += *((_pos)++); ) - -#define Deserialize_int_1(_pos, _val) STMT(\ - (_val) = *((_pos)++); ) - -#define Deserialize_int_2(_pos, _val) STMT(\ - Deserialize_int_1(_pos, _val); \ - __shift_de(_pos, _val); ) - -#define Deserialize_int_3(_pos, _val) STMT(\ - Deserialize_int_2(_pos, _val); \ - __shift_de(_pos, _val); ) - -#define Deserialize_int_4(_pos, _val) STMT(\ - Deserialize_int_3(_pos, _val); \ - __shift_de(_pos, _val); ) - -#define Deserialize_int_8(_pos, _val) STMT(\ - uint32 _v1; uint32 _v2; \ - Deserialize_int_4(_pos, _v1); \ - Deserialize_int_4(_pos, _v2); \ - _val = _v1; \ - _val <<= 32; /* janwas: careful! (uint32 << 32) = 0 */ \ - _val |= _v2; ) - -/** - * An interface for serializable objects. For a serializable object to be usable - * as a network message field, it must have a constructor without arguments. - */ -class ISerializable -{ -public: - virtual ~ISerializable() {} - - /** - * Return the length of the serialized form of this object - */ - virtual size_t GetSerializedLength() const = 0; - /** - * Serialize the object into the passed buffer. - * - * @return a pointer to the location in the buffer right after the - * serialized object - */ - virtual u8 *Serialize(u8 *buffer) const = 0; - /** - * Deserialize the object (i.e. read in data from the buffer and initialize - * the object's fields). Note that it is up to the deserializer to detect - * errors in data format. - * - * @param buffer A pointer pointing to the start of the serialized data. - * @param end A pointer to the end of the message. - * - * @returns a pointer to the location in the buffer right after the - * serialized object, or NULL if there was a data format error - */ - virtual const u8 *Deserialize(const u8 *buffer, const u8 *end) = 0; -}; - -#endif Index: source/network/StringConverters.h =================================================================== --- source/network/StringConverters.h +++ /dev/null @@ -1,38 +0,0 @@ -/* Copyright (C) 2011 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#ifndef INCLUDED_NETWORK_STRINGCONVERTERS -#define INCLUDED_NETWORK_STRINGCONVERTERS - -#include "ps/CStr.h" - -static inline CStr NetMessageStringConvert(u32 arg) -{ - return CStr::FromUInt(arg); -} - -static inline CStr NetMessageStringConvert(const CStr8& arg) -{ - return arg.EscapeToPrintableASCII(); -} - -static inline CStr NetMessageStringConvert(const CStrW& arg) -{ - return arg.EscapeToPrintableASCII(); -} - -#endif Index: source/network/fsm.h =================================================================== --- source/network/fsm.h +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright (C) 2015 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -#ifndef FSM_H -#define FSM_H - -// INCLUDES -#include -#include -#include - -// DECLARATIONS -#define FSM_INVALID_STATE ( unsigned int )( ~0 ) - -class CFsmEvent; -class CFsmTransition; -class CFsm; - -typedef bool ( *CONDITION ) ( void* pContext ); -typedef bool ( *ACTION ) ( void* pContext, const CFsmEvent* pEvent ); - -typedef struct -{ - void* pFunction; - void* pContext; - -} CallbackFunction; - -typedef std::set< unsigned int > StateSet; -typedef std::map< unsigned int, CFsmEvent* > EventMap; -typedef std::vector< CFsmTransition* > TransitionList; -typedef std::vector< CallbackFunction > CallbackList; - -/** - * Represents a signal in the state machine that a change has occurred. - * The CFsmEvent objects are under the control of CFsm so - * they are created and deleted via CFsm. - */ -class CFsmEvent -{ - NONCOPYABLE(CFsmEvent); -public: - - CFsmEvent( unsigned int type ); - ~CFsmEvent( void ); - - unsigned int GetType ( void ) const { return m_Type; } - void* GetParamRef ( void ) { return m_Param; } - void SetParamRef ( void* pParam ); - -private: - unsigned int m_Type; // Event type - void* m_Param; // Event paramater -}; - - -/** - * An association of event, condition, action and next state. - */ -class CFsmTransition -{ - NONCOPYABLE(CFsmTransition); -public: - - CFsmTransition( unsigned int state ); - ~CFsmTransition( void ); - - void RegisterAction ( - void* pAction, - void* pContext ); - void RegisterCondition ( - void* pCondition, - void* pContext ); - void SetEvent ( CFsmEvent* pEvent ); - CFsmEvent* GetEvent ( void ) const { return m_Event; } - void SetNextState ( unsigned int nextState ); - unsigned int GetNextState ( void ) const { return m_NextState; } - unsigned int GetCurrState ( void ) const { return m_CurrState; } - const CallbackList& GetActions ( void ) const { return m_Actions; } - const CallbackList& GetConditions ( void ) const { return m_Conditions; } - bool ApplyConditions ( void ) const; - bool RunActions ( void ) const; - -private: - unsigned int m_CurrState; // Current state - unsigned int m_NextState; // Next state - CFsmEvent* m_Event; // Transition event - CallbackList m_Actions; // List of actions for transition - CallbackList m_Conditions; // List of conditions for transition -}; - -/** - * Manages states, events, actions and transitions - * between states. It provides an interface for advertising - * events and track the current state. The implementation is - * a Mealy state machine, so the system respond to events - * and execute some action. - * - * A Mealy state machine has behaviour associated with state - * transitions; Mealy machines are event driven where an - * event triggers a state transition - */ -class CFsm -{ - NONCOPYABLE(CFsm); -public: - - CFsm( void ); - virtual ~CFsm( void ); - - /** - * Constructs the state machine. This method must be overriden so that - * connections are constructed for the particular state machine implemented - */ - virtual void Setup( void ); - - /** - * Clear event, action and condition lists and reset state machine - */ - void Shutdown( void ); - - void AddState ( unsigned int state ); - CFsmEvent* AddEvent ( unsigned int eventType ); - CFsmTransition* AddTransition ( - unsigned int state, - unsigned int eventType, - unsigned int nextState ); - CFsmTransition* AddTransition ( - unsigned int state, - unsigned int eventType, - unsigned int nextState, - void* pAction, - void* pContext ); - CFsmTransition* GetTransition ( - unsigned int state, - unsigned int eventType ) const; - CFsmTransition* GetEventTransition ( unsigned int eventType ) const; - void SetFirstState ( unsigned int firstState ); - void SetCurrState ( unsigned int state ); - unsigned int GetCurrState ( void ) const { return m_CurrState; } - void SetNextState ( unsigned int nextState ) { m_NextState = nextState; } - unsigned int GetNextState ( void ) const { return m_NextState; } - const StateSet& GetStates ( void ) const { return m_States; } - const EventMap& GetEvents ( void ) const { return m_Events; } - const TransitionList& GetTransitions ( void ) const { return m_Transitions; } - bool Update ( unsigned int eventType, void* pEventData ); - bool IsValidState ( unsigned int state ) const; - bool IsValidEvent ( unsigned int eventType ) const; - virtual bool IsDone ( void ) const; - -private: - bool IsFirstTime ( void ) const; - - bool m_Done; // FSM work is done - unsigned int m_FirstState; // Initial state - unsigned int m_CurrState; // Current state - unsigned int m_NextState; // Next state - StateSet m_States; // List of states - EventMap m_Events; // List of events - TransitionList m_Transitions; // State transitions -}; - -#endif // FSM_H - Index: source/network/fsm.cpp =================================================================== --- source/network/fsm.cpp +++ /dev/null @@ -1,470 +0,0 @@ -/* Copyright (C) 2015 Wildfire Games. - * This file is part of 0 A.D. - * - * 0 A.D. 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 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. 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 0 A.D. If not, see . - */ - -// INCLUDES -#include "precompiled.h" -#include "fsm.h" - -// DECLARATIONS - -//----------------------------------------------------------------------------- -// Name: CFsmEvent() -// Desc: Constructor -//----------------------------------------------------------------------------- -CFsmEvent::CFsmEvent( unsigned int type ) -{ - m_Type = type; - m_Param = NULL; -} - -//----------------------------------------------------------------------------- -// Name; ~CFsmEvent() -// Desc: Destructor -//----------------------------------------------------------------------------- -CFsmEvent::~CFsmEvent( void ) -{ - m_Param = NULL; -} - -//----------------------------------------------------------------------------- -// Name: SetParamRef() -// Desc: Sets the parameter for the event -//----------------------------------------------------------------------------- -void CFsmEvent::SetParamRef( void* pParam ) -{ - m_Param = pParam; -} - -//----------------------------------------------------------------------------- -// Name: CFsmTransition() -// Desc: Constructor -//----------------------------------------------------------------------------- -CFsmTransition::CFsmTransition( unsigned int state ) -{ - m_CurrState = state; -} - -//----------------------------------------------------------------------------- -// Name: ~CFsmTransition() -// Desc: Destructor -//----------------------------------------------------------------------------- -CFsmTransition::~CFsmTransition( void ) -{ - m_Actions.clear(); - m_Conditions.clear(); -} - -//----------------------------------------------------------------------------- -// Name: RegisterAction() -// Desc: Adds action that will be executed when the transition will occur -//----------------------------------------------------------------------------- -void CFsmTransition::RegisterAction( void* pAction, void* pContext ) -{ - CallbackFunction callback; - - // Add action at the end of actions list - callback.pFunction = pAction; - callback.pContext = pContext; - - m_Actions.push_back( callback ); -} - -//----------------------------------------------------------------------------- -// Name: AddCondition() -// Desc: Adds condition which will be evaluated when the transition will occurs -//----------------------------------------------------------------------------- -void CFsmTransition::RegisterCondition( void* pCondition, void* pContext ) -{ - CallbackFunction callback; - - // Add condition at the end of conditions list - callback.pFunction = pCondition; - callback.pContext = pContext; - - m_Conditions.push_back( callback ); -} - -//----------------------------------------------------------------------------- -// Name: SetEvent() -// Desc: Set event for which transition will occur -//----------------------------------------------------------------------------- -void CFsmTransition::SetEvent( CFsmEvent* pEvent ) -{ - m_Event = pEvent; -} - -//----------------------------------------------------------------------------- -// Name: SetNextState() -// Desc: Set next state the transition will switch the system to -//----------------------------------------------------------------------------- -void CFsmTransition::SetNextState( unsigned int nextState ) -{ - m_NextState = nextState; -} - -//----------------------------------------------------------------------------- -// Name: ApplyConditions() -// Desc: Evaluate conditions for the transition -// Note: If there are no conditions, assume true -//----------------------------------------------------------------------------- -bool CFsmTransition::ApplyConditions( void ) const -{ - bool eval = true; - - CallbackList::const_iterator it = m_Conditions.begin(); - for( ; it != m_Conditions.end(); ++it ) - { - if ( it->pFunction ) - { - // Evaluate condition - CONDITION Condition = ( CONDITION )it->pFunction; - eval &= Condition( it->pContext ); - } - } - - return eval; -} - -//----------------------------------------------------------------------------- -// Name: RunActions() -// Desc: Execute actions for the transition -// Note: If there are no actions, assume true -//----------------------------------------------------------------------------- -bool CFsmTransition::RunActions( void ) const -{ - bool result = true; - - CallbackList::const_iterator it = m_Actions.begin(); - for( ; it != m_Actions.end(); ++it ) - { - if ( it->pFunction ) - { - // Run action - ACTION Action = ( ACTION )it->pFunction; - result &= Action( it->pContext, m_Event ); - } - } - - return result; -} - -//----------------------------------------------------------------------------- -// Name: CFsm() -// Desc: Constructor -//----------------------------------------------------------------------------- -CFsm::CFsm( void ) -{ - m_Done = false; - m_FirstState = FSM_INVALID_STATE; - m_CurrState = FSM_INVALID_STATE; - m_NextState = FSM_INVALID_STATE; -} - -//----------------------------------------------------------------------------- -// Name: ~CFsm() -// Desc: Destructor -//----------------------------------------------------------------------------- -CFsm::~CFsm( void ) -{ - Shutdown(); -} - -//----------------------------------------------------------------------------- -// Name: Setup() -// Desc: Setup events, actions and state transitions -//----------------------------------------------------------------------------- -void CFsm::Setup( void ) -{ - // Does nothing by default -} - -//----------------------------------------------------------------------------- -// Name: Reset() -// Desc: Shuts down the state machine and releases any resources -//----------------------------------------------------------------------------- -void CFsm::Shutdown( void ) -{ - // Release transitions - TransitionList::iterator itTransition = m_Transitions.begin(); - for ( ; itTransition < m_Transitions.end(); ++itTransition ) - { - CFsmTransition* pCurrTransition = *itTransition; - if ( !pCurrTransition ) continue; - - delete pCurrTransition; - } - - // Release events - EventMap::iterator itEvent = m_Events.begin(); - for( ; itEvent != m_Events.end(); ++itEvent ) - { - CFsmEvent* pCurrEvent = itEvent->second; - if ( !pCurrEvent ) continue; - - delete pCurrEvent; - } - - m_States.clear(); - m_Events.clear(); - m_Transitions.clear(); - - m_Done = false; - m_FirstState = FSM_INVALID_STATE; - m_CurrState = FSM_INVALID_STATE; - m_NextState = FSM_INVALID_STATE; -} - -//----------------------------------------------------------------------------- -// Name: AddState() -// Desc: Adds the specified state to the internal list of states -// Note: If a state with the specified ID exists, the state is not added -//----------------------------------------------------------------------------- -void CFsm::AddState( unsigned int state ) -{ - m_States.insert( state ); -} - -//----------------------------------------------------------------------------- -// Name: AddEvent() -// Desc: Adds the specified event to the internal list of events -// Note: If an eveny with the specified ID exists, the event is not added -//----------------------------------------------------------------------------- -CFsmEvent* CFsm::AddEvent( unsigned int eventType ) -{ - CFsmEvent* pEvent = NULL; - - // Lookup event by type - EventMap::iterator it = m_Events.find( eventType ); - if ( it != m_Events.end() ) - { - pEvent = it->second; - } - else - { - pEvent = new CFsmEvent( eventType ); - if ( !pEvent ) return NULL; - - // Store new event into internal map - m_Events[ eventType ] = pEvent; - } - - return pEvent; -} - -//----------------------------------------------------------------------------- -// Name: AddTransition() -// Desc: Adds a new transistion to the state machine -//----------------------------------------------------------------------------- -CFsmTransition* CFsm::AddTransition( - unsigned int state, - unsigned int eventType, - unsigned int nextState ) -{ - // Make sure we store the current state - AddState( state ); - - // Make sure we store the next state - AddState( nextState ); - - // Make sure we store the event - CFsmEvent* pEvent = AddEvent( eventType ); - if ( !pEvent ) return NULL; - - // Create new transition - CFsmTransition* pNewTransition = new CFsmTransition( state ); - if ( !pNewTransition ) - { - delete pEvent; - return NULL; - } - - // Setup new transition - pNewTransition->SetEvent( pEvent ); - pNewTransition->SetNextState( nextState ); - - // Store new transition - m_Transitions.push_back( pNewTransition ); - - return pNewTransition; -} - -//----------------------------------------------------------------------------- -// Name: AddTransition() -// Desc: Adds a new transition to the state machine -//----------------------------------------------------------------------------- -CFsmTransition* CFsm::AddTransition( - unsigned int state, - unsigned int eventType, - unsigned int nextState, - void* pAction, - void* pContext ) -{ - CFsmTransition* pTransition = AddTransition( state, eventType, nextState ); - if ( !pTransition ) return NULL; - - // If action specified, register it - if ( pAction ) - pTransition->RegisterAction( pAction, pContext ); - - return pTransition; -} - -//----------------------------------------------------------------------------- -// Name: GetTransition() -// Desc: Lookup transition given the state, event and next state to transition -//----------------------------------------------------------------------------- -CFsmTransition* CFsm::GetTransition( - unsigned int state, - unsigned int eventType ) const -{ - // Valid state? - if ( !IsValidState( state ) ) return NULL; - - // Valid event? - if ( !IsValidEvent( eventType ) ) return NULL; - - // Loop through the list of transitions - TransitionList::const_iterator it = m_Transitions.begin(); - for ( ; it != m_Transitions.end(); ++it ) - { - CFsmTransition* pCurrTransition = *it; - if ( !pCurrTransition ) continue; - - CFsmEvent* pCurrEvent = pCurrTransition->GetEvent(); - if ( !pCurrEvent ) continue; - - // Is it our transition? - if ( pCurrTransition->GetCurrState() == state && - pCurrEvent->GetType() == eventType ) - { - return pCurrTransition; - } - } - - // No transition found - return NULL; -} - -//----------------------------------------------------------------------------- -// Name: SetFirstState() -// Desc: Set initial state for FSM -//----------------------------------------------------------------------------- -void CFsm::SetFirstState( unsigned int firstState ) -{ - m_FirstState = firstState; -} - -//----------------------------------------------------------------------------- -// Name: SetCurrState() -// Desc: Set current state and update last state to current state -//----------------------------------------------------------------------------- -void CFsm::SetCurrState( unsigned int state ) -{ - m_CurrState = state; -} - -//----------------------------------------------------------------------------- -// Name: IsFirstTime() -// Desc: Verifies if the state machine has been already updated -//----------------------------------------------------------------------------- -bool CFsm::IsFirstTime( void ) const -{ - return ( m_CurrState == FSM_INVALID_STATE ); -} - -//----------------------------------------------------------------------------- -// Name: Update() -// Desc: Updates state machine and retrieves next state -//----------------------------------------------------------------------------- -bool CFsm::Update( unsigned int eventType, void* pEventParam ) -{ - // Valid event? - if ( !IsValidEvent( eventType ) ) - return false; - - // First time update? - if ( IsFirstTime() ) - m_CurrState = m_FirstState; - - // Lookup transition - CFsmTransition* pTransition = GetTransition( m_CurrState, eventType ); - if ( !pTransition ) - return false; - - // Setup event parameter - EventMap::iterator it = m_Events.find( eventType ); - if ( it != m_Events.end() ) - { - CFsmEvent* pEvent = it->second; - if ( pEvent ) pEvent->SetParamRef( pEventParam ); - } - - // Valid transition? - if ( !pTransition->ApplyConditions() ) - return false; - - // Save the default state transition (actions might call SetNextState - // to override this) - SetNextState( pTransition->GetNextState() ); - - // Run transition actions - if ( !pTransition->RunActions() ) - return false; - - // Switch state - SetCurrState( GetNextState() ); - - // Reset the next state since it's no longer valid - SetNextState( FSM_INVALID_STATE ); - - return true; -} - -//----------------------------------------------------------------------------- -// Name: IsDone() -// Desc: Tests whether the state machine has finished its work -// Note: This is state machine specific -//----------------------------------------------------------------------------- -bool CFsm::IsDone( void ) const -{ - // By default the internal flag m_Done is tested - return m_Done; -} - -//----------------------------------------------------------------------------- -// Name: IsValidState() -// Desc: Verifies whether the specified state is managed by FSM -//----------------------------------------------------------------------------- -bool CFsm::IsValidState( unsigned int state ) const -{ - StateSet::const_iterator it = m_States.find( state ); - if ( it == m_States.end() ) return false; - - return true; -} - -//----------------------------------------------------------------------------- -// Name: IsValidEvent() -// Desc: Verifies whether the specified event is managed by FSM -//----------------------------------------------------------------------------- -bool CFsm::IsValidEvent( unsigned int eventType ) const -{ - EventMap::const_iterator it = m_Events.find( eventType ); - if ( it == m_Events.end() ) return false; - - return true; -} Index: source/network/tests/test_Net.h =================================================================== --- source/network/tests/test_Net.h +++ source/network/tests/test_Net.h @@ -23,8 +23,6 @@ #include "lib/tex/tex.h" #include "network/NetServer.h" #include "network/NetClient.h" -#include "network/NetMessage.h" -#include "network/NetMessages.h" #include "ps/CLogger.h" #include "ps/Game.h" #include "ps/Filesystem.h" Index: source/network/tests/test_NetMessage.h =================================================================== --- source/network/tests/test_NetMessage.h +++ source/network/tests/test_NetMessage.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,14 +17,76 @@ #include "lib/self_test.h" -#include "network/NetMessage.h" +#include "network/NetMessages.h" #include "scriptinterface/ScriptInterface.h" +/** + * Test a representative subset of messages for serialization and deserialization. + */ class TestNetMessage : public CxxTest::TestSuite { public: - void test_sim() + void test_CSrvHandshakeMessage() + { + CSrvHandshakeMessage msg; + msg.m_Magic = PS_PROTOCOL_MAGIC; + msg.m_ProtocolVersion = PS_PROTOCOL_VERSION; + msg.m_SoftwareVersion = PS_PROTOCOL_VERSION; + CNetMessageBuffer buffer(msg); + CSrvHandshakeMessage msg2(buffer); + TS_ASSERT_EQUALS(msg.m_Magic, msg2.m_Magic); + TS_ASSERT_EQUALS(msg.m_ProtocolVersion, msg2.m_ProtocolVersion); + TS_ASSERT_EQUALS(msg.m_SoftwareVersion, msg2.m_SoftwareVersion); + } + + void test_CAuthenticateMessage() + { + CAuthenticateMessage msg; + msg.m_GUID = "ABDgIHIfaH519af35709adfhhjkdeai!#!$19"; + msg.m_Name = L"#*$AH73HHFA2j6Oet((#_!)63HFA"; + msg.m_Password = L"r#@*Q(8ehVZsw**#I@!Jhrf28951"; + msg.m_IsLocalClient = true; + CNetMessageBuffer buffer(msg); + CAuthenticateMessage msg2(buffer); + TS_ASSERT_EQUALS(msg.m_GUID, msg2.m_GUID); + TS_ASSERT_EQUALS(msg.m_Name, msg2.m_Name); + TS_ASSERT_EQUALS(msg.m_Password, msg2.m_Password); + TS_ASSERT_EQUALS(msg.m_IsLocalClient, msg2.m_IsLocalClient); + } + + void test_CPlayerAssignmentMessage() + { + CPlayerAssignmentMessage::SHost host1; + host1.m_GUID = "HFI#*@*!((*%*!!((VZ9395410uvFAfa9qj"; + host1.m_Name = L"AIH9310hfAjo3920!#$!(&<<."; + host1.m_PlayerID = -105; + host1.m_Status = 250; + CPlayerAssignmentMessage::SHost host2; + host2.m_GUID = "HFIASF#i6-0@9u62-u---0gji20%G"; + host2.m_Name = L"gs$$!#$!(&$Y44gGE<."; + host2.m_PlayerID = 57; + host2.m_Status = 0; + + CPlayerAssignmentMessage msg; + msg.m_Hosts.push_back(host1); + msg.m_Hosts.push_back(host2); + + CNetMessageBuffer buffer(msg); + CPlayerAssignmentMessage msg2(buffer); + + TS_ASSERT_EQUALS(host1.m_GUID, msg2.m_Hosts[0].m_GUID); + TS_ASSERT_EQUALS(host1.m_Name, msg2.m_Hosts[0].m_Name); + TS_ASSERT_EQUALS(host1.m_PlayerID, msg2.m_Hosts[0].m_PlayerID); + TS_ASSERT_EQUALS(host1.m_Status, msg2.m_Hosts[0].m_Status); + + TS_ASSERT_EQUALS(host2.m_GUID, msg2.m_Hosts[1].m_GUID); + TS_ASSERT_EQUALS(host2.m_Name, msg2.m_Hosts[1].m_Name); + TS_ASSERT_EQUALS(host2.m_PlayerID, msg2.m_Hosts[1].m_PlayerID); + TS_ASSERT_EQUALS(host2.m_Status, msg2.m_Hosts[1].m_Status); + } + + void test_CSimulationMessage() { ScriptInterface script("Test", "Test", g_ScriptRuntime); JSContext* cx = script.GetContext(); @@ -33,18 +95,14 @@ JS::RootedValue val(cx); script.Eval("[4]", &val); CSimulationMessage msg(script, 1, 2, 3, val); - TS_ASSERT_STR_EQUALS(msg.ToString(), "CSimulationMessage { m_Client: 1, m_Player: 2, m_Turn: 3, m_Data: [4] }"); - size_t len = msg.GetSerializedLength(); - u8* buf = new u8[len+1]; - buf[len] = '!'; - TS_ASSERT_EQUALS(msg.Serialize(buf) - (buf+len), 0); - TS_ASSERT_EQUALS(buf[len], '!'); + CNetMessageBuffer buffer(msg); - CNetMessage* msg2 = CNetMessageFactory::CreateMessage(buf, len, script); - TS_ASSERT_STR_EQUALS(((CSimulationMessage*)msg2)->ToString(), "CSimulationMessage { m_Client: 1, m_Player: 2, m_Turn: 3, m_Data: [4] }"); + CSimulationMessage msg2(script, buffer); - delete msg2; - delete[] buf; + TS_ASSERT_EQUALS(msg.m_Client, msg2.m_Client); + TS_ASSERT_EQUALS(msg.m_Player, msg2.m_Player); + TS_ASSERT_EQUALS(msg.m_Turn, msg2.m_Turn); + TS_ASSERT_STR_EQUALS(script.ToString(&msg.m_JSData.m_Data), script.ToString(&msg2.m_JSData.m_Data)); } }; Index: source/ps/CStr.h =================================================================== --- source/ps/CStr.h +++ source/ps/CStr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -332,13 +332,6 @@ // Calculates a hash of the string's contents size_t GetHashCode() const; - - // Serialization functions - // (These are not virtual or inherited from ISerializable, to avoid - // adding a vtable and making the strings larger than std::string) - size_t GetSerializedLength() const; - u8* Serialize(u8* buffer) const; - const u8* Deserialize(const u8* buffer, const u8* bufferend); }; static inline size_t hash_value(const CStr& s) Index: source/ps/CStr.cpp =================================================================== --- source/ps/CStr.cpp +++ source/ps/CStr.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2014 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -28,8 +28,6 @@ #include "lib/fnv_hash.h" #include "lib/utf8.h" -#include "lib/byte_order.h" -#include "network/Serialization.h" #include #include @@ -37,7 +35,6 @@ #define UNIDOUBLER_HEADER "CStr.cpp" #include "UniDoubler.h" - // Only include these function definitions in the first instance of CStr.cpp: /** @@ -434,81 +431,6 @@ // the result was truncated down to 32 anyway. } -#ifdef _UNICODE -/* - CStrW is always serialized to/from UTF-16 -*/ - -u8* CStrW::Serialize(u8* buffer) const -{ - size_t len = length(); - size_t i = 0; - for (i = 0; i < len; i++) - { - const u16 bigEndian = to_be16((*this)[i]); - *(u16 *)(buffer + i*2) = bigEndian; - } - *(u16 *)(buffer + i*2) = 0; - return buffer + len*2 + 2; -} - -const u8* CStrW::Deserialize(const u8* buffer, const u8* bufferend) -{ - const u16 *strend = (const u16 *)buffer; - while ((const u8 *)strend < bufferend && *strend) strend++; - if ((const u8 *)strend >= bufferend) return NULL; - - resize(strend - (const u16 *)buffer); - const u16 *ptr = (const u16 *)buffer; - - std::wstring::iterator str = begin(); - while (ptr < strend) - { - const u16 native = to_be16(*(ptr++)); // we want from_be16, but that's the same - *(str++) = (tchar)native; - } - - return (const u8 *)(strend+1); -} - -size_t CStr::GetSerializedLength() const -{ - return size_t(length()*2 + 2); -} - -#else -/* - CStr8 is always serialized to/from ASCII (or whatever 8-bit codepage stored - in the CStr) -*/ - -u8* CStr8::Serialize(u8* buffer) const -{ - size_t len = length(); - Serialize_int_4(buffer, (u32)len); - size_t i = 0; - for (i = 0; i < len; i++) - buffer[i] = (*this)[i]; - return buffer + len; -} - -const u8* CStr8::Deserialize(const u8* buffer, const u8* bufferend) -{ - u32 len; - Deserialize_int_4(buffer, len); - if (buffer + len > bufferend) - return NULL; - *this = std::string(buffer, buffer + len); - return buffer + len; -} - -size_t CStr::GetSerializedLength() const -{ - return length() + 4; -} - -#endif // _UNICODE - // Clean up, to keep the second pass through unidoubler happy #undef tstringstream #undef _tstod Index: source/ps/GameSetup/GameSetup.cpp =================================================================== --- source/ps/GameSetup/GameSetup.cpp +++ source/ps/GameSetup/GameSetup.cpp @@ -49,7 +49,6 @@ #include "maths/MathUtil.h" #include "network/NetServer.h" #include "network/NetClient.h" -#include "network/NetMessage.h" #include "network/NetMessages.h" #include "ps/CConsole.h" Index: source/ps/tests/test_CStr.h =================================================================== --- source/ps/tests/test_CStr.h +++ source/ps/tests/test_CStr.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2010 Wildfire Games. +/* Copyright (C) 2017 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -75,38 +75,6 @@ } } - template - void roundtrip(const T& str) - { - size_t len = str.GetSerializedLength(); - u8* buf = new u8[len+1]; - buf[len] = '!'; - TS_ASSERT_EQUALS(str.Serialize(buf) - (buf+len), 0); - TS_ASSERT_EQUALS(buf[len], '!'); - - T str2; - TS_ASSERT_EQUALS(str2.Deserialize(buf, buf+len) - (buf+len), 0); - TS_ASSERT_EQUALS(str2.length(), str.length()); - TS_ASSERT_EQUALS(str2, str); - - T str3; - TS_ASSERT_EQUALS(str3.Deserialize(buf, buf+len+256) - (buf+len), 0); - TS_ASSERT_EQUALS(str3.length(), str.length()); - TS_ASSERT_EQUALS(str3, str); - - delete[] buf; - } - - void test_serialize_8() - { - CStr8 str1("hello"); - roundtrip(str1); - - CStr8 str2 = str1; - str2[3] = '\0'; - roundtrip(str2); - } - void test_parse() { // Parsing should be independent of locale ("," vs "."),