Line data Source code
1 : /* Copyright (C) 2020 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 "ComponentManager.h"
21 : #include "IComponent.h"
22 : #include "ParamNode.h"
23 :
24 : #include "simulation2/MessageTypes.h"
25 :
26 : #include "simulation2/serialization/DebugSerializer.h"
27 : #include "simulation2/serialization/HashSerializer.h"
28 : #include "simulation2/serialization/StdSerializer.h"
29 : #include "simulation2/serialization/StdDeserializer.h"
30 :
31 : #include "simulation2/components/ICmpTemplateManager.h"
32 :
33 : #include "ps/CLogger.h"
34 :
35 7 : std::string SerializeRNG(const boost::random::rand48& rng)
36 : {
37 14 : std::stringstream s;
38 7 : s << rng;
39 14 : return s.str();
40 : }
41 :
42 3 : void DeserializeRNG(const std::string& str, boost::random::rand48& rng)
43 : {
44 6 : std::stringstream s;
45 3 : s << str;
46 3 : s >> rng;
47 3 : }
48 :
49 2 : bool CComponentManager::DumpDebugState(std::ostream& stream, bool includeDebugInfo) const
50 : {
51 4 : CDebugSerializer serializer(m_ScriptInterface, stream, includeDebugInfo);
52 :
53 2 : serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
54 :
55 2 : serializer.TextLine("entities:");
56 :
57 : // We want the output to be grouped by entity ID, so invert the CComponentManager data structures
58 4 : std::map<entity_id_t, std::map<ComponentTypeId, IComponent*> > components;
59 : //std::map<ComponentTypeId, std::string> names;
60 :
61 2 : std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator ctit = m_ComponentsByTypeId.begin();
62 14 : for (; ctit != m_ComponentsByTypeId.end(); ++ctit)
63 : {
64 6 : std::map<entity_id_t, IComponent*>::const_iterator eit = ctit->second.begin();
65 22 : for (; eit != ctit->second.end(); ++eit)
66 : {
67 8 : components[eit->first][ctit->first] = eit->second;
68 : }
69 : }
70 :
71 2 : std::map<entity_id_t, std::map<ComponentTypeId, IComponent*> >::const_iterator cit = components.begin();
72 16 : for (; cit != components.end(); ++cit)
73 : {
74 14 : std::stringstream n;
75 7 : n << "- id: " << cit->first;
76 7 : serializer.TextLine(n.str());
77 :
78 7 : if (ENTITY_IS_LOCAL(cit->first))
79 1 : serializer.TextLine(" type: local");
80 :
81 7 : std::map<ComponentTypeId, IComponent*>::const_iterator it = cit->second.begin();
82 23 : for (; it != cit->second.end(); ++it)
83 : {
84 16 : std::stringstream st;
85 8 : st << " " << LookupComponentTypeName(it->first) << ":";
86 8 : serializer.TextLine(st.str());
87 8 : serializer.Indent(4);
88 8 : it->second->Serialize(serializer);
89 8 : serializer.Dedent(4);
90 : }
91 7 : serializer.TextLine("");
92 : }
93 :
94 : // TODO: catch exceptions
95 4 : return true;
96 : }
97 :
98 1 : bool CComponentManager::ComputeStateHash(std::string& outHash, bool quick) const
99 : {
100 : // Hash serialization: this includes the minimal data necessary to detect
101 : // differences in the state, and ignores things like counts and names
102 :
103 : // If 'quick' is set, this checks even fewer things, so that it will
104 : // be fast enough to run every turn but will typically detect any
105 : // out-of-syncs fairly soon
106 :
107 2 : CHashSerializer serializer(m_ScriptInterface);
108 :
109 1 : serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
110 1 : serializer.NumberU32_Unbounded("next entity id", m_NextEntityId);
111 :
112 1 : std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator cit = m_ComponentsByTypeId.begin();
113 5 : for (; cit != m_ComponentsByTypeId.end(); ++cit)
114 : {
115 : // In quick mode, only check unit positions
116 2 : if (quick && !(cit->first == CID_Position))
117 0 : continue;
118 :
119 : // Only emit component types if they have a component that will be serialized
120 2 : bool needsSerialization = false;
121 2 : for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
122 : {
123 : // Don't serialize local entities
124 2 : if (ENTITY_IS_LOCAL(eit->first))
125 0 : continue;
126 :
127 2 : needsSerialization = true;
128 2 : break;
129 : }
130 :
131 2 : if (!needsSerialization)
132 0 : continue;
133 :
134 2 : serializer.NumberI32_Unbounded("component type id", cit->first);
135 :
136 6 : for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
137 : {
138 : // Don't serialize local entities
139 4 : if (ENTITY_IS_LOCAL(eit->first))
140 1 : continue;
141 :
142 3 : serializer.NumberU32_Unbounded("entity id", eit->first);
143 3 : eit->second->Serialize(serializer);
144 : }
145 : }
146 :
147 1 : outHash = std::string((const char*)serializer.ComputeHash(), serializer.GetHashLength());
148 :
149 : // TODO: catch exceptions
150 2 : return true;
151 : }
152 :
153 : /*
154 : * Simulation state serialization format:
155 : *
156 : * TODO: Global version number.
157 : * Number of SYSTEM_ENTITY component types
158 : * For each SYSTEM_ENTITY component type:
159 : * Component type name
160 : * TODO: Component type version number.
161 : * Component state.
162 : * Number of (non-empty, non-SYSTEM_ENTITY-only) component types.
163 : * For each component type:
164 : * Component type name.
165 : * TODO: Component type version number.
166 : * Number of entities.
167 : * For each entity:
168 : * Entity id.
169 : * Component state.
170 : *
171 : * Rationale:
172 : * Saved games should be valid across patches, which might change component
173 : * type IDs. Thus the names are serialized, not the IDs.
174 : * Version numbers are used so saved games from future versions can be rejected,
175 : * and those from older versions can be fixed up to work with the latest version.
176 : * (These aren't really needed for networked games (where everyone will have the same
177 : * version), but it doesn't seem worth having a separate codepath for that.)
178 : */
179 :
180 4 : bool CComponentManager::SerializeState(std::ostream& stream) const
181 : {
182 8 : CStdSerializer serializer(m_ScriptInterface, stream);
183 :
184 : // We don't serialize the destruction queue, since we'd have to be careful to skip local entities etc.
185 : // This means we cannot have non-local entities in the destruction queue at this point.
186 4 : ENSURE(m_DestructionQueue.empty() || std::find_if(m_DestructionQueue.begin(), m_DestructionQueue.end(),
187 : [](entity_id_t ent) { return !ENTITY_IS_LOCAL(ent); }) == m_DestructionQueue.end());
188 :
189 4 : serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32);
190 4 : serializer.NumberU32_Unbounded("next entity id", m_NextEntityId);
191 :
192 4 : std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator cit;
193 :
194 4 : uint32_t numSystemComponentTypes = 0;
195 4 : uint32_t numComponentTypes = 0;
196 8 : std::set<ComponentTypeId> serializedSystemComponentTypes;
197 8 : std::set<ComponentTypeId> serializedComponentTypes;
198 :
199 13 : for (cit = m_ComponentsByTypeId.begin(); cit != m_ComponentsByTypeId.end(); ++cit)
200 : {
201 : // Only emit component types if they have a component that will be serialized
202 9 : bool needsSerialization = false;
203 12 : for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
204 : {
205 : // Don't serialize local entities, and handle SYSTEM_ENTITY separately
206 9 : if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
207 3 : continue;
208 :
209 6 : needsSerialization = true;
210 6 : break;
211 : }
212 :
213 9 : if (needsSerialization)
214 : {
215 6 : numComponentTypes++;
216 6 : serializedComponentTypes.insert(cit->first);
217 : }
218 :
219 9 : if (cit->second.find(SYSTEM_ENTITY) != cit->second.end())
220 : {
221 3 : numSystemComponentTypes++;
222 3 : serializedSystemComponentTypes.insert(cit->first);
223 : }
224 : }
225 :
226 4 : serializer.NumberU32_Unbounded("num system component types", numSystemComponentTypes);
227 :
228 12 : for (cit = m_ComponentsByTypeId.begin(); cit != m_ComponentsByTypeId.end(); ++cit)
229 : {
230 9 : if (serializedSystemComponentTypes.find(cit->first) == serializedSystemComponentTypes.end())
231 6 : continue;
232 :
233 3 : std::map<ComponentTypeId, ComponentType>::const_iterator ctit = m_ComponentTypesById.find(cit->first);
234 3 : if (ctit == m_ComponentTypesById.end())
235 : {
236 0 : debug_warn(L"Invalid ctit"); // this should never happen
237 0 : return false;
238 : }
239 :
240 3 : serializer.StringASCII("name", ctit->second.name, 0, 255);
241 :
242 3 : std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.find(SYSTEM_ENTITY);
243 3 : if (eit == cit->second.end())
244 : {
245 0 : debug_warn(L"Invalid eit"); // this should never happen
246 0 : return false;
247 : }
248 3 : eit->second->Serialize(serializer);
249 : }
250 :
251 3 : serializer.NumberU32_Unbounded("num component types", numComponentTypes);
252 :
253 11 : for (cit = m_ComponentsByTypeId.begin(); cit != m_ComponentsByTypeId.end(); ++cit)
254 : {
255 8 : if (serializedComponentTypes.find(cit->first) == serializedComponentTypes.end())
256 2 : continue;
257 :
258 6 : std::map<ComponentTypeId, ComponentType>::const_iterator ctit = m_ComponentTypesById.find(cit->first);
259 6 : if (ctit == m_ComponentTypesById.end())
260 : {
261 0 : debug_warn(L"Invalid ctit"); // this should never happen
262 0 : return false;
263 : }
264 :
265 6 : serializer.StringASCII("name", ctit->second.name, 0, 255);
266 :
267 : // Count the components before serializing any of them
268 6 : uint32_t numComponents = 0;
269 14 : for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
270 : {
271 : // Don't serialize local entities or SYSTEM_ENTITY
272 8 : if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
273 1 : continue;
274 :
275 7 : numComponents++;
276 : }
277 :
278 : // Emit the count
279 6 : serializer.NumberU32_Unbounded("num components", numComponents);
280 :
281 : // Serialize the components now
282 14 : for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit)
283 : {
284 : // Don't serialize local entities or SYSTEM_ENTITY
285 8 : if (ENTITY_IS_LOCAL(eit->first) || eit->first == SYSTEM_ENTITY)
286 1 : continue;
287 :
288 7 : serializer.NumberU32_Unbounded("entity id", eit->first);
289 7 : eit->second->Serialize(serializer);
290 : }
291 : }
292 :
293 : // TODO: catch exceptions
294 3 : return true;
295 : }
296 :
297 3 : bool CComponentManager::DeserializeState(std::istream& stream)
298 : {
299 : try
300 : {
301 6 : CStdDeserializer deserializer(m_ScriptInterface, stream);
302 :
303 3 : ResetState();
304 3 : InitSystemEntity();
305 :
306 6 : std::string rng;
307 3 : deserializer.StringASCII("rng", rng, 0, 32);
308 3 : DeserializeRNG(rng, m_RNG);
309 :
310 3 : deserializer.NumberU32_Unbounded("next entity id", m_NextEntityId); // TODO: use sensible bounds
311 :
312 : uint32_t numSystemComponentTypes;
313 3 : deserializer.NumberU32_Unbounded("num system component types", numSystemComponentTypes);
314 :
315 3 : ICmpTemplateManager* templateManager = NULL;
316 6 : CParamNode noParam;
317 :
318 5 : for (size_t i = 0; i < numSystemComponentTypes; ++i)
319 : {
320 4 : std::string ctname;
321 2 : deserializer.StringASCII("name", ctname, 0, 255);
322 :
323 2 : ComponentTypeId ctid = LookupCID(ctname);
324 2 : if (ctid == CID__Invalid)
325 : {
326 0 : LOGERROR("Deserialization saw unrecognised component type '%s'", ctname.c_str());
327 0 : return false;
328 : }
329 :
330 2 : IComponent* component = ConstructComponent(m_SystemEntity, ctid);
331 2 : if (!component)
332 0 : return false;
333 :
334 2 : component->Deserialize(noParam, deserializer);
335 :
336 : // If this was the template manager, remember it so we can use it when
337 : // deserializing any further non-system entities
338 2 : if (ctid == CID_TemplateManager)
339 1 : templateManager = static_cast<ICmpTemplateManager*> (component);
340 : }
341 :
342 : uint32_t numComponentTypes;
343 3 : deserializer.NumberU32_Unbounded("num component types", numComponentTypes);
344 :
345 9 : for (size_t i = 0; i < numComponentTypes; ++i)
346 : {
347 12 : std::string ctname;
348 6 : deserializer.StringASCII("name", ctname, 0, 255);
349 :
350 6 : ComponentTypeId ctid = LookupCID(ctname);
351 6 : if (ctid == CID__Invalid)
352 : {
353 0 : LOGERROR("Deserialization saw unrecognised component type '%s'", ctname.c_str());
354 0 : return false;
355 : }
356 :
357 : uint32_t numComponents;
358 6 : deserializer.NumberU32_Unbounded("num components", numComponents);
359 :
360 13 : for (size_t j = 0; j < numComponents; ++j)
361 : {
362 : entity_id_t ent;
363 7 : deserializer.NumberU32_Unbounded("entity id", ent);
364 7 : IComponent* component = ConstructComponent(LookupEntityHandle(ent, true), ctid);
365 7 : if (!component)
366 0 : return false;
367 :
368 : // Try to find the template for this entity
369 7 : const CParamNode* entTemplate = NULL;
370 7 : if (templateManager)
371 1 : entTemplate = templateManager->LoadLatestTemplate(ent);
372 :
373 : // Deserialize, with the appropriate template for this component
374 7 : if (entTemplate)
375 1 : component->Deserialize(entTemplate->GetChild(ctname.c_str()), deserializer);
376 : else
377 6 : component->Deserialize(noParam, deserializer);
378 : }
379 : }
380 :
381 3 : if (stream.peek() != EOF)
382 : {
383 0 : LOGERROR("Deserialization didn't reach EOF");
384 0 : return false;
385 : }
386 :
387 : // Allow components to do some final reinitialisation after everything is loaded
388 6 : CMessageDeserialized msg;
389 3 : BroadcastMessage(msg);
390 :
391 3 : return true;
392 : }
393 0 : catch (PSERROR_Deserialize& e)
394 : {
395 0 : LOGERROR("Deserialization failed: %s", e.what());
396 0 : return false;
397 : }
398 3 : }
|