bool CComponentManager::ComputeStateHash(std::string& outHash, bool quick) { // Hash serialization: this includes the minimal data necessary to detect // differences in the state, and ignores things like counts and names // If 'quick' is set, this checks even fewer things, so that it will // be fast enough to run every turn but will typically detect any // out-of-syncs fairly soon CHashSerializer serializer(m_ScriptInterface); serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator cit = m_ComponentsByTypeId.begin(); for (; cit != m_ComponentsByTypeId.end(); ++cit) { // In quick mode, only check unit positions if (quick && !(cit->first == CID_Position)) continue; // Only emit component types if they have a component that will be serialized bool needsSerialization = false; for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities if (ENTITY_IS_LOCAL(eit->first)) continue; needsSerialization = true; break; } if (!needsSerialization) continue; serializer.NumberI32_Unbounded("component type id", cit->first); for (std::map<entity_id_t, IComponent*>::const_iterator eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities if (ENTITY_IS_LOCAL(eit->first)) continue; serializer.NumberU32_Unbounded("entity id", eit->first); eit->second->Serialize(serializer); } } outHash = std::string((const char*)serializer.ComputeHash(), serializer.GetHashLength()); // TODO: catch exceptions return true; }
bool CComponentManager::DumpDebugState(std::ostream& stream) { CDebugSerializer serializer(m_ScriptInterface, stream); serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); serializer.TextLine("entities:"); // We want the output to be grouped by entity ID, so invert the CComponentManager data structures std::map<entity_id_t, std::map<ComponentTypeId, IComponent*> > components; std::map<ComponentTypeId, std::string> names; std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator ctit = m_ComponentsByTypeId.begin(); for (; ctit != m_ComponentsByTypeId.end(); ++ctit) { std::map<entity_id_t, IComponent*>::const_iterator eit = ctit->second.begin(); for (; eit != ctit->second.end(); ++eit) { components[eit->first][ctit->first] = eit->second; } } std::map<entity_id_t, std::map<ComponentTypeId, IComponent*> >::const_iterator cit = components.begin(); for (; cit != components.end(); ++cit) { std::stringstream n; n << "- id: " << cit->first; serializer.TextLine(n.str()); if (ENTITY_IS_LOCAL(cit->first)) serializer.TextLine(" type: local"); std::map<ComponentTypeId, IComponent*>::const_iterator ctit = cit->second.begin(); for (; ctit != cit->second.end(); ++ctit) { std::stringstream n; n << " " << LookupComponentTypeName(ctit->first) << ":"; serializer.TextLine(n.str()); serializer.Indent(4); ctit->second->Serialize(serializer); serializer.Dedent(4); } serializer.TextLine(""); } // TODO: catch exceptions return true; }
bool CComponentManager::SerializeState(std::ostream& stream) { CStdSerializer serializer(m_ScriptInterface, stream); // We don't serialize the destruction queue, since we'd have to be careful to skip local entities etc // and it's (hopefully) easier to just expect callers to flush the queue before serializing ENSURE(m_DestructionQueue.empty()); serializer.StringASCII("rng", SerializeRNG(m_RNG), 0, 32); serializer.NumberU32_Unbounded("next entity id", m_NextEntityId); uint32_t numComponentTypes = 0; std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator cit; for (cit = m_ComponentsByTypeId.begin(); cit != m_ComponentsByTypeId.end(); ++cit) { if (cit->second.empty()) continue; numComponentTypes++; } serializer.NumberU32_Unbounded("num component types", numComponentTypes); for (cit = m_ComponentsByTypeId.begin(); cit != m_ComponentsByTypeId.end(); ++cit) { if (cit->second.empty()) continue; std::map<ComponentTypeId, ComponentType>::const_iterator ctit = m_ComponentTypesById.find(cit->first); if (ctit == m_ComponentTypesById.end()) { debug_warn(L"Invalid ctit"); // this should never happen return false; } serializer.StringASCII("name", ctit->second.name, 0, 255); std::map<entity_id_t, IComponent*>::const_iterator eit; // Count the components before serializing any of them uint32_t numComponents = 0; for (eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities if (ENTITY_IS_LOCAL(eit->first)) continue; numComponents++; } // Emit the count serializer.NumberU32_Unbounded("num components", numComponents); // Serialize the components now for (eit = cit->second.begin(); eit != cit->second.end(); ++eit) { // Don't serialize local entities if (ENTITY_IS_LOCAL(eit->first)) continue; serializer.NumberU32_Unbounded("entity id", eit->first); eit->second->Serialize(serializer); } } // TODO: catch exceptions return true; }