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;
}
Exemple #2
0
void CComponentManager::SendGlobalMessage(entity_id_t ent, const CMessage& msg) const
{
	// (Common functionality for PostMessage and BroadcastMessage)

	// Send the message to components of all entities that subscribed globally to this message
	std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
	it = m_GlobalMessageSubscriptions.find(msg.GetType());
	if (it != m_GlobalMessageSubscriptions.end())
	{
		std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
		for (; ctit != it->second.end(); ++ctit)
		{
			// Special case: Messages for non-local entities shouldn't be sent to script
			// components that subscribed globally, so that we don't have to worry about
			// them accidentally picking up non-network-synchronised data.
			if (ENTITY_IS_LOCAL(ent))
			{
				std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(*ctit);
				if (it != m_ComponentTypesById.end() && it->second.type == CT_Script)
					continue;
			}

			// Find the component instances of this type (if any)
			std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
			if (emap == m_ComponentsByTypeId.end())
				continue;

			// Send the message to all of them
			std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
			for (; eit != emap->second.end(); ++eit)
				eit->second->HandleMessage(msg, true);
		}
	}
}
Exemple #3
0
std::vector<int> CComponentManager::Script_GetEntitiesWithInterface(ScriptInterface::CxPrivate* pCxPrivate, int iid)
{
	CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData);

	std::vector<int> ret;
	const InterfaceListUnordered& ents = componentManager->GetEntitiesWithInterfaceUnordered(iid);
	for (InterfaceListUnordered::const_iterator it = ents.begin(); it != ents.end(); ++it)
		if (!ENTITY_IS_LOCAL(it->first))
			ret.push_back(it->first);
	std::sort(ret.begin(), ret.end());
	return ret;
}
Exemple #4
0
    virtual void Serialize(ISerializer& serialize)
    {
        size_t count = 0;

        for (std::map<entity_id_t, std::string>::const_iterator it = m_LatestTemplates.begin(); it != m_LatestTemplates.end(); ++it)
        {
            if (ENTITY_IS_LOCAL(it->first))
                continue;
            ++count;
        }
        serialize.NumberU32_Unbounded("num entities", (u32)count);

        for (std::map<entity_id_t, std::string>::const_iterator it = m_LatestTemplates.begin(); it != m_LatestTemplates.end(); ++it)
        {
            if (ENTITY_IS_LOCAL(it->first))
                continue;
            serialize.NumberU32_Unbounded("id", it->first);
            serialize.StringASCII("template", it->second, 0, 256);
        }
        // TODO: maybe we should do some kind of interning thing instead of printing so many strings?

        // TODO: will need to serialize techs too, because we need to be giving out
        // template data before other components (like the tech components) have been deserialized
    }
Exemple #5
0
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;
}
Exemple #6
0
	virtual void Init(const CParamNode& paramNode)
	{
		m_Active = !paramNode.GetChild("Inactive").IsOk();
		m_DelayTime = paramNode.GetChild("DelayTime").ToFixed().ToFloat();
		m_SinkRate = paramNode.GetChild("SinkRate").ToFixed().ToFloat();
		m_SinkAccel = paramNode.GetChild("SinkAccel").ToFixed().ToFloat();

		m_CurrentTime = 0.f;
		m_TotalSinkDepth = -1.f;

		// Detect unsafe misconfiguration
		if (m_Active && !ENTITY_IS_LOCAL(GetEntityId()))
		{
			debug_warn(L"CCmpDecay must not be used on non-local (network-synchronised) entities");
			m_Active = false;
		}
	}
Exemple #7
0
void CComponentManager::SendGlobalMessage(entity_id_t ent, const CMessage& msg)
{
	PROFILE2_IFSPIKE("SendGlobalMessage", 0.001);
	PROFILE2_ATTR("%s", msg.GetScriptHandlerName());
	// (Common functionality for PostMessage and BroadcastMessage)

	// Send the message to components of all entities that subscribed globally to this message
	std::map<MessageTypeId, std::vector<ComponentTypeId> >::const_iterator it;
	it = m_GlobalMessageSubscriptions.find(msg.GetType());
	if (it != m_GlobalMessageSubscriptions.end())
	{
		std::vector<ComponentTypeId>::const_iterator ctit = it->second.begin();
		for (; ctit != it->second.end(); ++ctit)
		{
			// Special case: Messages for local entities shouldn't be sent to script
			// components that subscribed globally, so that we don't have to worry about
			// them accidentally picking up non-network-synchronised data.
			if (ENTITY_IS_LOCAL(ent))
			{
				std::map<ComponentTypeId, ComponentType>::const_iterator it = m_ComponentTypesById.find(*ctit);
				if (it != m_ComponentTypesById.end() && it->second.type == CT_Script)
					continue;
			}

			// Find the component instances of this type (if any)
			std::map<ComponentTypeId, std::map<entity_id_t, IComponent*> >::const_iterator emap = m_ComponentsByTypeId.find(*ctit);
			if (emap == m_ComponentsByTypeId.end())
				continue;

			// Send the message to all of them
			std::map<entity_id_t, IComponent*>::const_iterator eit = emap->second.begin();
			for (; eit != emap->second.end(); ++eit)
				eit->second->HandleMessage(msg, true);
		}
	}

	// Send the message to component instances that dynamically subscribed to this message
	std::map<MessageTypeId, CDynamicSubscription>::iterator dit = m_DynamicMessageSubscriptionsNonsync.find(msg.GetType());
	if (dit != m_DynamicMessageSubscriptionsNonsync.end())
	{
		dit->second.Flatten();
		const std::vector<IComponent*>& dynamic = dit->second.GetComponents();
		for (size_t i = 0; i < dynamic.size(); i++)
			dynamic[i]->HandleMessage(msg, false);
	}
}
Exemple #8
0
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;
}
Exemple #9
0
void CMapWriter::WriteXML(const VfsPath& filename,
						  WaterManager* pWaterMan, SkyManager* pSkyMan,
						  CLightEnv* pLightEnv, CCamera* pCamera, CCinemaManager* pCinema,
						  CPostprocManager* pPostproc,
						  CSimulation2* pSimulation2)
{
	XML_Start();

	{
		XML_Element("Scenario");
		XML_Attribute("version", (int)FILE_VERSION);

		ENSURE(pSimulation2);
		CSimulation2& sim = *pSimulation2;

		if (!sim.GetStartupScript().empty())
		{
			XML_Element("Script");
			XML_CDATA(sim.GetStartupScript().c_str());
		}

		{
			XML_Element("Environment");

			XML_Setting("SkySet", pSkyMan->GetSkySet());
			{
				XML_Element("SunColor");
				XML_Attribute("r", pLightEnv->m_SunColor.X); // yes, it's X/Y/Z...
				XML_Attribute("g", pLightEnv->m_SunColor.Y);
				XML_Attribute("b", pLightEnv->m_SunColor.Z);
			}
			{
				XML_Element("SunElevation");
				XML_Attribute("angle", pLightEnv->m_Elevation);
			}
			{
				XML_Element("SunRotation");
				XML_Attribute("angle", pLightEnv->m_Rotation);
			}
			{
				XML_Element("TerrainAmbientColor");
				XML_Attribute("r", pLightEnv->m_TerrainAmbientColor.X);
				XML_Attribute("g", pLightEnv->m_TerrainAmbientColor.Y);
				XML_Attribute("b", pLightEnv->m_TerrainAmbientColor.Z);
			}
			{
				XML_Element("UnitsAmbientColor");
				XML_Attribute("r", pLightEnv->m_UnitsAmbientColor.X);
				XML_Attribute("g", pLightEnv->m_UnitsAmbientColor.Y);
				XML_Attribute("b", pLightEnv->m_UnitsAmbientColor.Z);
			}
			{
				XML_Element("Fog");
				XML_Setting("FogFactor", pLightEnv->m_FogFactor);
				XML_Setting("FogThickness", pLightEnv->m_FogMax);
				{
					XML_Element("FogColor");
					XML_Attribute("r", pLightEnv->m_FogColor.X);
					XML_Attribute("g", pLightEnv->m_FogColor.Y);
					XML_Attribute("b", pLightEnv->m_FogColor.Z);
				}
			}

			{
				XML_Element("Water");
				{
					XML_Element("WaterBody");
					CmpPtr<ICmpWaterManager> cmpWaterManager(sim, SYSTEM_ENTITY);
					ENSURE(cmpWaterManager);
					XML_Setting("Type", pWaterMan->m_WaterType);
					{
						XML_Element("Color");
						XML_Attribute("r", pWaterMan->m_WaterColor.r);
						XML_Attribute("g", pWaterMan->m_WaterColor.g);
						XML_Attribute("b", pWaterMan->m_WaterColor.b);
					}
					{
						XML_Element("Tint");
						XML_Attribute("r", pWaterMan->m_WaterTint.r);
						XML_Attribute("g", pWaterMan->m_WaterTint.g);
						XML_Attribute("b", pWaterMan->m_WaterTint.b);
					}
					XML_Setting("Height", cmpWaterManager->GetExactWaterLevel(0, 0));
					XML_Setting("Waviness", pWaterMan->m_Waviness);
					XML_Setting("Murkiness", pWaterMan->m_Murkiness);
					XML_Setting("WindAngle", pWaterMan->m_WindAngle);
				}
			}

			{
				XML_Element("Postproc");
				{
					XML_Setting("Brightness", pLightEnv->m_Brightness);
					XML_Setting("Contrast", pLightEnv->m_Contrast);
					XML_Setting("Saturation", pLightEnv->m_Saturation);
					XML_Setting("Bloom", pLightEnv->m_Bloom);
					XML_Setting("PostEffect", pPostproc->GetPostEffect());
				}
			}
		}

		{
			XML_Element("Camera");

			{
				XML_Element("Position");
				CVector3D pos = pCamera->m_Orientation.GetTranslation();
				XML_Attribute("x", pos.X);
				XML_Attribute("y", pos.Y);
				XML_Attribute("z", pos.Z);
			}

			CVector3D in = pCamera->m_Orientation.GetIn();
			// Convert to spherical coordinates
			float rotation = atan2(in.X, in.Z);
			float declination = atan2(sqrt(in.X*in.X + in.Z*in.Z), in.Y) - (float)M_PI/2;

			{
				XML_Element("Rotation");
				XML_Attribute("angle", rotation);
			}
			{
				XML_Element("Declination");
				XML_Attribute("angle", declination);
			}
		}

		{
			std::string settings = sim.GetMapSettingsString();
			if (!settings.empty())
			{
				XML_Element("ScriptSettings");
				XML_CDATA(("\n" + settings + "\n").c_str());
			}
		}

		{
			XML_Element("Entities");

			CmpPtr<ICmpTemplateManager> cmpTemplateManager(sim, SYSTEM_ENTITY);
			ENSURE(cmpTemplateManager);

			// This will probably need to be changed in the future, but for now we'll
			// just save all entities that have a position
			CSimulation2::InterfaceList ents = sim.GetEntitiesWithInterface(IID_Position);
			for (CSimulation2::InterfaceList::const_iterator it = ents.begin(); it != ents.end(); ++it)
			{
				entity_id_t ent = it->first;

				// Don't save local entities (placement previews etc)
				if (ENTITY_IS_LOCAL(ent))
					continue;

				XML_Element("Entity");
				XML_Attribute("uid", ent);

				XML_Setting("Template", cmpTemplateManager->GetCurrentTemplateName(ent));

				CmpPtr<ICmpOwnership> cmpOwnership(sim, ent);
				if (cmpOwnership)
					XML_Setting("Player", (int)cmpOwnership->GetOwner());

				CmpPtr<ICmpPosition> cmpPosition(sim, ent);
				if (cmpPosition)
				{
					CFixedVector3D pos;
					if (cmpPosition->IsInWorld())
						pos = cmpPosition->GetPosition();

					CFixedVector3D rot = cmpPosition->GetRotation();
					{
						XML_Element("Position");
						XML_Attribute("x", pos.X);
						XML_Attribute("z", pos.Z);
						// TODO: height offset etc
					}
					{
						XML_Element("Orientation");
						XML_Attribute("y", rot.Y);
						// TODO: X, Z maybe
					}
				}

				CmpPtr<ICmpObstruction> cmpObstruction(sim, ent);
				if (cmpObstruction)
				{
					// TODO: Currently only necessary because Atlas
					// does not set up control groups for its walls.
					cmpObstruction->ResolveFoundationCollisions();

					entity_id_t group = cmpObstruction->GetControlGroup();
					entity_id_t group2 = cmpObstruction->GetControlGroup2();

					// Don't waste space writing the default control groups.
					if (group != ent || group2 != INVALID_ENTITY)
					{
						XML_Element("Obstruction");
						if (group != ent)
							XML_Attribute("group", group);
						if (group2 != INVALID_ENTITY)
							XML_Attribute("group2", group2);
					}
				}

				CmpPtr<ICmpVisual> cmpVisual(sim, ent);
				if (cmpVisual)
				{
					u32 seed = cmpVisual->GetActorSeed();
					if (seed != (u32)ent)
					{
						XML_Element("Actor");
						XML_Attribute("seed", seed);
					}
					// TODO: variation/selection strings
				}
			}
		}

		const std::map<CStrW, CCinemaPath>& paths = pCinema->GetAllPaths();
		std::map<CStrW, CCinemaPath>::const_iterator it = paths.begin();

		{
			XML_Element("Paths");

			for ( ; it != paths.end(); ++it )
			{
				fixed timescale = it->second.GetTimescale();
				const std::vector<SplineData>& nodes = it->second.GetAllNodes();
				const std::vector<SplineData>& target_nodes = it->second.GetTargetSpline().GetAllNodes();
				const CCinemaData* data = it->second.GetData();
				
				XML_Element("Path");
				XML_Attribute("name", data->m_Name);
				XML_Attribute("timescale", timescale);
				XML_Attribute("orientation", data->m_Orientation);
				XML_Attribute("mode", data->m_Mode);
				XML_Attribute("style", data->m_Style);

				fixed last_target = fixed::Zero();
				for (size_t i = 0, j = 0; i < nodes.size(); ++i)
				{
					XML_Element("Node");
					fixed distance = i > 0 ? nodes[i - 1].Distance : fixed::Zero();
					last_target += distance;

					XML_Attribute("deltatime", distance);

					{
						XML_Element("Position");
						XML_Attribute("x", nodes[i].Position.X);
						XML_Attribute("y", nodes[i].Position.Y);
						XML_Attribute("z", nodes[i].Position.Z);
					}

					{
						XML_Element("Rotation");
						XML_Attribute("x", nodes[i].Rotation.X);
						XML_Attribute("y", nodes[i].Rotation.Y);
						XML_Attribute("z", nodes[i].Rotation.Z);
					}

					if (j >= target_nodes.size())
						continue;

					fixed target_distance = j > 0 ? target_nodes[j - 1].Distance : fixed::Zero();

					if (target_distance > last_target)
						continue;

					{
						XML_Element("Target");
						XML_Attribute("x", target_nodes[j].Position.X);
						XML_Attribute("y", target_nodes[j].Position.Y);
						XML_Attribute("z", target_nodes[j].Position.Z);
					}

					last_target = fixed::Zero();
					++j;
				}
			}
		}
	}
	if (!XML_StoreVFS(g_VFS, filename))
		LOGERROR("Failed to write map '%s'", filename.string8());
}