LCOV - code coverage report
Current view: top level - source/network - NetMessageSim.cpp (source / functions) Hit Total Coverage
Test: 0 A.D. test coverage report Lines: 64 103 62.1 %
Date: 2023-01-19 00:18:29 Functions: 16 25 64.0 %

          Line data    Source code
       1             : /* Copyright (C) 2021 Wildfire Games.
       2             :  * This file is part of 0 A.D.
       3             :  *
       4             :  * 0 A.D. is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 2 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * 0 A.D. is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "precompiled.h"
      19             : 
      20             : #include "NetMessage.h"
      21             : 
      22             : #include "lib/utf8.h"
      23             : #include "scriptinterface/ScriptRequest.h"
      24             : #include "scriptinterface/JSON.h"
      25             : #include "simulation2/serialization/BinarySerializer.h"
      26             : #include "simulation2/serialization/StdDeserializer.h"
      27             : #include "simulation2/serialization/StdSerializer.h" // for DEBUG_SERIALIZER_ANNOTATE
      28             : 
      29             : #include <sstream>
      30             : 
      31             : class CBufferBinarySerializerImpl
      32             : {
      33             : public:
      34           1 :     CBufferBinarySerializerImpl(u8* buffer) :
      35           1 :         m_Buffer(buffer)
      36             :     {
      37           1 :     }
      38             : 
      39          11 :     void Put(const char* name, const u8* data, size_t len)
      40             :     {
      41             :         #if DEBUG_SERIALIZER_ANNOTATE
      42             :             std::string tag = "<";
      43             :             tag.append(name);
      44             :             tag.append(">");
      45             :             memcpy(m_Buffer, tag.c_str(), tag.length());
      46             :             m_Buffer += tag.length();
      47             :         #else
      48             :             UNUSED2(name);
      49             :         #endif
      50          11 :         memcpy(m_Buffer, data, len);
      51          11 :         m_Buffer += len;
      52          11 :     }
      53             : 
      54             :     u8* m_Buffer;
      55             : };
      56             : 
      57             : /**
      58             :  * Serializer instance that writes directly to a buffer (which must be long enough).
      59             :  */
      60           1 : class CBufferBinarySerializer : public CBinarySerializer<CBufferBinarySerializerImpl>
      61             : {
      62             : public:
      63           1 :     CBufferBinarySerializer(const ScriptInterface& scriptInterface, u8* buffer) :
      64           1 :         CBinarySerializer<CBufferBinarySerializerImpl>(scriptInterface, buffer)
      65             :     {
      66           1 :     }
      67             : 
      68           1 :     u8* GetBuffer()
      69             :     {
      70           1 :         return m_Impl.m_Buffer;
      71             :     }
      72             : };
      73             : 
      74             : class CLengthBinarySerializerImpl
      75             : {
      76             : public:
      77           2 :     CLengthBinarySerializerImpl() :
      78           2 :         m_Length(0)
      79             :     {
      80           2 :     }
      81             : 
      82          22 :     void Put(const char* name, const u8* UNUSED(data), size_t len)
      83             :     {
      84             :         #if DEBUG_SERIALIZER_ANNOTATE
      85             :         m_Length += 2;  // '<' and '>'
      86             :         m_Length += strlen(name);
      87             :         #else
      88             :             UNUSED2(name);
      89             :         #endif
      90          22 :         m_Length += len;
      91          22 :     }
      92             : 
      93             :     size_t m_Length;
      94             : };
      95             : 
      96             : /**
      97             :  * Serializer instance that simply counts how many bytes would be written.
      98             :  */
      99           2 : class CLengthBinarySerializer : public CBinarySerializer<CLengthBinarySerializerImpl>
     100             : {
     101             : public:
     102           2 :     CLengthBinarySerializer(const ScriptInterface& scriptInterface) :
     103           2 :         CBinarySerializer<CLengthBinarySerializerImpl>(scriptInterface)
     104             :     {
     105           2 :     }
     106             : 
     107           2 :     size_t GetLength()
     108             :     {
     109           2 :         return m_Impl.m_Length;
     110             :     }
     111             : };
     112             : 
     113           1 : CSimulationMessage::CSimulationMessage(const ScriptInterface& scriptInterface) :
     114           1 :     CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface)
     115             : {
     116           2 :     ScriptRequest rq(scriptInterface);
     117           1 :     m_Data.init(rq.cx);
     118           1 : }
     119             : 
     120           1 : CSimulationMessage::CSimulationMessage(const ScriptInterface& scriptInterface, u32 client, i32 player, u32 turn, JS::HandleValue data) :
     121             :     CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface),
     122           1 :     m_Client(client), m_Player(player), m_Turn(turn)
     123             : {
     124           2 :     ScriptRequest rq(scriptInterface);
     125           1 :     m_Data.init(rq.cx, data);
     126           1 : }
     127             : 
     128           0 : CSimulationMessage::CSimulationMessage(const CSimulationMessage& orig) :
     129           0 :     m_Client(orig.m_Client),
     130           0 :     m_Player(orig.m_Player),
     131           0 :     m_ScriptInterface(orig.m_ScriptInterface),
     132           0 :     m_Turn(orig.m_Turn),
     133           0 :     CNetMessage(orig)
     134             : {
     135           0 :     ScriptRequest rq(m_ScriptInterface);
     136           0 :     m_Data.init(rq.cx, orig.m_Data);
     137           0 : }
     138             : 
     139           1 : u8* CSimulationMessage::Serialize(u8* pBuffer) const
     140             : {
     141             :     // TODO: ought to handle serialization exceptions
     142             :     // TODO: ought to represent common commands more efficiently
     143           1 :     u8* pos = CNetMessage::Serialize(pBuffer);
     144           2 :     CBufferBinarySerializer serializer(m_ScriptInterface, pos);
     145           1 :     serializer.NumberU32_Unbounded("client", m_Client);
     146           1 :     serializer.NumberI32_Unbounded("player", m_Player);
     147           1 :     serializer.NumberU32_Unbounded("turn", m_Turn);
     148             : 
     149           1 :     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     150           2 :     return serializer.GetBuffer();
     151             : }
     152             : 
     153           1 : const u8* CSimulationMessage::Deserialize(const u8* pStart, const u8* pEnd)
     154             : {
     155             :     // TODO: ought to handle serialization exceptions
     156             :     // TODO: ought to represent common commands more efficiently
     157           1 :     const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
     158           2 :     std::istringstream stream(std::string(pos, pEnd));
     159           2 :     CStdDeserializer deserializer(m_ScriptInterface, stream);
     160           1 :     deserializer.NumberU32_Unbounded("client", m_Client);
     161           1 :     deserializer.NumberI32_Unbounded("player", m_Player);
     162           1 :     deserializer.NumberU32_Unbounded("turn", m_Turn);
     163           1 :     deserializer.ScriptVal("command", &m_Data);
     164           2 :     return pEnd;
     165             : }
     166             : 
     167           2 : size_t CSimulationMessage::GetSerializedLength() const
     168             : {
     169             :     // TODO: serializing twice is stupidly inefficient - we should just
     170             :     // do it once, store the result, and use it here and in Serialize
     171           4 :     CLengthBinarySerializer serializer(m_ScriptInterface);
     172           2 :     serializer.NumberU32_Unbounded("client", m_Client);
     173           2 :     serializer.NumberI32_Unbounded("player", m_Player);
     174           2 :     serializer.NumberU32_Unbounded("turn", m_Turn);
     175             : 
     176             :     // TODO: The cast can probably be removed if and when ScriptVal can take a JS::HandleValue instead of
     177             :     // a JS::MutableHandleValue (relies on JSAPI change). Also search for other casts like this one in that case.
     178           2 :     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     179           4 :     return CNetMessage::GetSerializedLength() + serializer.GetLength();
     180             : }
     181             : 
     182           2 : CStr CSimulationMessage::ToString() const
     183             : {
     184           4 :     std::string source = Script::ToString(ScriptRequest(m_ScriptInterface), const_cast<JS::PersistentRootedValue*>(&m_Data));
     185             : 
     186           4 :     std::stringstream stream;
     187           2 :     stream << "CSimulationMessage { m_Client: " << m_Client << ", m_Player: " << m_Player << ", m_Turn: " << m_Turn << ", m_Data: " << source << " }";
     188           4 :     return CStr(stream.str());
     189             : }
     190             : 
     191             : 
     192           0 : CGameSetupMessage::CGameSetupMessage(const ScriptInterface& scriptInterface) :
     193           0 :     CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface)
     194             : {
     195           0 :     ScriptRequest rq(m_ScriptInterface);
     196           0 :     m_Data.init(rq.cx);
     197           0 : }
     198             : 
     199           0 : CGameSetupMessage::CGameSetupMessage(const ScriptInterface& scriptInterface, JS::HandleValue data) :
     200           0 :     CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface)
     201             : {
     202           0 :     ScriptRequest rq(m_ScriptInterface);
     203           0 :     m_Data.init(rq.cx, data);
     204           0 : }
     205             : 
     206           0 : u8* CGameSetupMessage::Serialize(u8* pBuffer) const
     207             : {
     208             :     // TODO: ought to handle serialization exceptions
     209           0 :     u8* pos = CNetMessage::Serialize(pBuffer);
     210           0 :     CBufferBinarySerializer serializer(m_ScriptInterface, pos);
     211           0 :     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     212           0 :     return serializer.GetBuffer();
     213             : }
     214             : 
     215           0 : const u8* CGameSetupMessage::Deserialize(const u8* pStart, const u8* pEnd)
     216             : {
     217             :     // TODO: ought to handle serialization exceptions
     218           0 :     const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
     219           0 :     std::istringstream stream(std::string(pos, pEnd));
     220           0 :     CStdDeserializer deserializer(m_ScriptInterface, stream);
     221           0 :     deserializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     222           0 :     return pEnd;
     223             : }
     224             : 
     225           0 : size_t CGameSetupMessage::GetSerializedLength() const
     226             : {
     227           0 :     CLengthBinarySerializer serializer(m_ScriptInterface);
     228           0 :     serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
     229           0 :     return CNetMessage::GetSerializedLength() + serializer.GetLength();
     230             : }
     231             : 
     232           0 : CStr CGameSetupMessage::ToString() const
     233             : {
     234           0 :     std::string source = Script::ToString(ScriptRequest(m_ScriptInterface), const_cast<JS::PersistentRootedValue*>(&m_Data));
     235             : 
     236           0 :     std::stringstream stream;
     237           0 :     stream << "CGameSetupMessage { m_Data: " << source << " }";
     238           0 :     return CStr(stream.str());
     239             : }

Generated by: LCOV version 1.13