Fixes calls to SetVertexAttributeFormat with zero stride.
[0ad.git] / source / network / NetMessageSim.cpp
blobda21354627a047eda129cda3991ec9d84cd13d90
1 /* Copyright (C) 2021 Wildfire Games.
2 * This file is part of 0 A.D.
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.
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.
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/>.
18 #include "precompiled.h"
20 #include "NetMessage.h"
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
29 #include <sstream>
31 class CBufferBinarySerializerImpl
33 public:
34 CBufferBinarySerializerImpl(u8* buffer) :
35 m_Buffer(buffer)
39 void Put(const char* name, const u8* data, size_t len)
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 memcpy(m_Buffer, data, len);
51 m_Buffer += len;
54 u8* m_Buffer;
57 /**
58 * Serializer instance that writes directly to a buffer (which must be long enough).
60 class CBufferBinarySerializer : public CBinarySerializer<CBufferBinarySerializerImpl>
62 public:
63 CBufferBinarySerializer(const ScriptInterface& scriptInterface, u8* buffer) :
64 CBinarySerializer<CBufferBinarySerializerImpl>(scriptInterface, buffer)
68 u8* GetBuffer()
70 return m_Impl.m_Buffer;
74 class CLengthBinarySerializerImpl
76 public:
77 CLengthBinarySerializerImpl() :
78 m_Length(0)
82 void Put(const char* name, const u8* UNUSED(data), size_t len)
84 #if DEBUG_SERIALIZER_ANNOTATE
85 m_Length += 2; // '<' and '>'
86 m_Length += strlen(name);
87 #else
88 UNUSED2(name);
89 #endif
90 m_Length += len;
93 size_t m_Length;
96 /**
97 * Serializer instance that simply counts how many bytes would be written.
99 class CLengthBinarySerializer : public CBinarySerializer<CLengthBinarySerializerImpl>
101 public:
102 CLengthBinarySerializer(const ScriptInterface& scriptInterface) :
103 CBinarySerializer<CLengthBinarySerializerImpl>(scriptInterface)
107 size_t GetLength()
109 return m_Impl.m_Length;
113 CSimulationMessage::CSimulationMessage(const ScriptInterface& scriptInterface) :
114 CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface)
116 ScriptRequest rq(scriptInterface);
117 m_Data.init(rq.cx);
120 CSimulationMessage::CSimulationMessage(const ScriptInterface& scriptInterface, u32 client, i32 player, u32 turn, JS::HandleValue data) :
121 CNetMessage(NMT_SIMULATION_COMMAND), m_ScriptInterface(scriptInterface),
122 m_Client(client), m_Player(player), m_Turn(turn)
124 ScriptRequest rq(scriptInterface);
125 m_Data.init(rq.cx, data);
128 CSimulationMessage::CSimulationMessage(const CSimulationMessage& orig) :
129 m_Client(orig.m_Client),
130 m_Player(orig.m_Player),
131 m_ScriptInterface(orig.m_ScriptInterface),
132 m_Turn(orig.m_Turn),
133 CNetMessage(orig)
135 ScriptRequest rq(m_ScriptInterface);
136 m_Data.init(rq.cx, orig.m_Data);
139 u8* CSimulationMessage::Serialize(u8* pBuffer) const
141 // TODO: ought to handle serialization exceptions
142 // TODO: ought to represent common commands more efficiently
143 u8* pos = CNetMessage::Serialize(pBuffer);
144 CBufferBinarySerializer serializer(m_ScriptInterface, pos);
145 serializer.NumberU32_Unbounded("client", m_Client);
146 serializer.NumberI32_Unbounded("player", m_Player);
147 serializer.NumberU32_Unbounded("turn", m_Turn);
149 serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
150 return serializer.GetBuffer();
153 const u8* CSimulationMessage::Deserialize(const u8* pStart, const u8* pEnd)
155 // TODO: ought to handle serialization exceptions
156 // TODO: ought to represent common commands more efficiently
157 const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
158 std::istringstream stream(std::string(pos, pEnd));
159 CStdDeserializer deserializer(m_ScriptInterface, stream);
160 deserializer.NumberU32_Unbounded("client", m_Client);
161 deserializer.NumberI32_Unbounded("player", m_Player);
162 deserializer.NumberU32_Unbounded("turn", m_Turn);
163 deserializer.ScriptVal("command", &m_Data);
164 return pEnd;
167 size_t CSimulationMessage::GetSerializedLength() const
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 CLengthBinarySerializer serializer(m_ScriptInterface);
172 serializer.NumberU32_Unbounded("client", m_Client);
173 serializer.NumberI32_Unbounded("player", m_Player);
174 serializer.NumberU32_Unbounded("turn", m_Turn);
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 serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
179 return CNetMessage::GetSerializedLength() + serializer.GetLength();
182 CStr CSimulationMessage::ToString() const
184 std::string source = Script::ToString(ScriptRequest(m_ScriptInterface), const_cast<JS::PersistentRootedValue*>(&m_Data));
186 std::stringstream stream;
187 stream << "CSimulationMessage { m_Client: " << m_Client << ", m_Player: " << m_Player << ", m_Turn: " << m_Turn << ", m_Data: " << source << " }";
188 return CStr(stream.str());
192 CGameSetupMessage::CGameSetupMessage(const ScriptInterface& scriptInterface) :
193 CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface)
195 ScriptRequest rq(m_ScriptInterface);
196 m_Data.init(rq.cx);
199 CGameSetupMessage::CGameSetupMessage(const ScriptInterface& scriptInterface, JS::HandleValue data) :
200 CNetMessage(NMT_GAME_SETUP), m_ScriptInterface(scriptInterface)
202 ScriptRequest rq(m_ScriptInterface);
203 m_Data.init(rq.cx, data);
206 u8* CGameSetupMessage::Serialize(u8* pBuffer) const
208 // TODO: ought to handle serialization exceptions
209 u8* pos = CNetMessage::Serialize(pBuffer);
210 CBufferBinarySerializer serializer(m_ScriptInterface, pos);
211 serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
212 return serializer.GetBuffer();
215 const u8* CGameSetupMessage::Deserialize(const u8* pStart, const u8* pEnd)
217 // TODO: ought to handle serialization exceptions
218 const u8* pos = CNetMessage::Deserialize(pStart, pEnd);
219 std::istringstream stream(std::string(pos, pEnd));
220 CStdDeserializer deserializer(m_ScriptInterface, stream);
221 deserializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
222 return pEnd;
225 size_t CGameSetupMessage::GetSerializedLength() const
227 CLengthBinarySerializer serializer(m_ScriptInterface);
228 serializer.ScriptVal("command", const_cast<JS::PersistentRootedValue*>(&m_Data));
229 return CNetMessage::GetSerializedLength() + serializer.GetLength();
232 CStr CGameSetupMessage::ToString() const
234 std::string source = Script::ToString(ScriptRequest(m_ScriptInterface), const_cast<JS::PersistentRootedValue*>(&m_Data));
236 std::stringstream stream;
237 stream << "CGameSetupMessage { m_Data: " << source << " }";
238 return CStr(stream.str());