Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/components/CCmpAIManager.cpp
Show First 20 Lines • Show All 90 Lines • ▼ Show 20 Lines | public: | ||||
} | } | ||||
bool Initialise() | bool Initialise() | ||||
{ | { | ||||
// LoadScripts will only load each script once even though we call it for each player | // LoadScripts will only load each script once even though we call it for each player | ||||
if (!m_Worker.LoadScripts(m_AIName)) | if (!m_Worker.LoadScripts(m_AIName)) | ||||
return false; | return false; | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; | OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; | ||||
JS::RootedValue metadata(rq.cx); | JS::RootedValue metadata(rq.cx); | ||||
m_Worker.LoadMetadata(path, &metadata); | m_Worker.LoadMetadata(path, &metadata); | ||||
if (metadata.isUndefined()) | if (metadata.isUndefined()) | ||||
{ | { | ||||
LOGERROR("Failed to create AI player: can't find %s", path.string8()); | LOGERROR("Failed to create AI player: can't find %s", path.string8()); | ||||
return false; | return false; | ||||
▲ Show 20 Lines • Show All 199 Lines • ▼ Show 20 Lines | void PostCommand(int playerid, JS::HandleValue cmd) | ||||
LOGERROR("Invalid playerid in PostCommand!"); | LOGERROR("Invalid playerid in PostCommand!"); | ||||
} | } | ||||
static JS::Value ComputePath(ScriptInterface::CmptPrivate* pCmptPrivate, | static JS::Value ComputePath(ScriptInterface::CmptPrivate* pCmptPrivate, | ||||
JS::HandleValue position, JS::HandleValue goal, pass_class_t passClass) | JS::HandleValue position, JS::HandleValue goal, pass_class_t passClass) | ||||
{ | { | ||||
ENSURE(pCmptPrivate->pCBData); | ENSURE(pCmptPrivate->pCBData); | ||||
CAIWorker* self = static_cast<CAIWorker*> (pCmptPrivate->pCBData); | CAIWorker* self = static_cast<CAIWorker*> (pCmptPrivate->pCBData); | ||||
ScriptInterface::Request rq(self->m_ScriptInterface); | ScriptRequest rq(self->m_ScriptInterface); | ||||
CFixedVector2D pos, goalPos; | CFixedVector2D pos, goalPos; | ||||
std::vector<CFixedVector2D> waypoints; | std::vector<CFixedVector2D> waypoints; | ||||
JS::RootedValue retVal(rq.cx); | JS::RootedValue retVal(rq.cx); | ||||
self->m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, position, pos); | self->m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, position, pos); | ||||
self->m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, goal, goalPos); | self->m_ScriptInterface->FromJSVal<CFixedVector2D>(rq, goal, goalPos); | ||||
▲ Show 20 Lines • Show All 73 Lines • ▼ Show 20 Lines | public: | ||||
void SetRNGSeed(u32 seed) | void SetRNGSeed(u32 seed) | ||||
{ | { | ||||
m_RNG.seed(seed); | m_RNG.seed(seed); | ||||
} | } | ||||
bool TryLoadSharedComponent() | bool TryLoadSharedComponent() | ||||
{ | { | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
// we don't need to load it. | // we don't need to load it. | ||||
if (!m_HasSharedComponent) | if (!m_HasSharedComponent) | ||||
return false; | return false; | ||||
// reset the value so it can be used to determine if we actually initialized it. | // reset the value so it can be used to determine if we actually initialized it. | ||||
m_HasSharedComponent = false; | m_HasSharedComponent = false; | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | public: | ||||
} | } | ||||
bool RunGamestateInit(const shared_ptr<ScriptInterface::StructuredClone>& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap, | bool RunGamestateInit(const shared_ptr<ScriptInterface::StructuredClone>& gameState, const Grid<NavcellData>& passabilityMap, const Grid<u8>& territoryMap, | ||||
const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks) | const std::map<std::string, pass_class_t>& nonPathfindingPassClassMasks, const std::map<std::string, pass_class_t>& pathfindingPassClassMasks) | ||||
{ | { | ||||
// this will be run last by InitGame.js, passing the full game representation. | // this will be run last by InitGame.js, passing the full game representation. | ||||
// For now it will run for the shared Component. | // For now it will run for the shared Component. | ||||
// This is NOT run during deserialization. | // This is NOT run during deserialization. | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
JS::RootedValue state(rq.cx); | JS::RootedValue state(rq.cx); | ||||
m_ScriptInterface->ReadStructuredClone(gameState, &state); | m_ScriptInterface->ReadStructuredClone(gameState, &state); | ||||
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, passabilityMap); | ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, passabilityMap); | ||||
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, territoryMap); | ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, territoryMap); | ||||
m_PassabilityMap = passabilityMap; | m_PassabilityMap = passabilityMap; | ||||
m_NonPathfindingPassClasses = nonPathfindingPassClassMasks; | m_NonPathfindingPassClasses = nonPathfindingPassClassMasks; | ||||
Show All 37 Lines | if (globallyDirty) | ||||
m_HierarchicalPathfinder.Recompute(&m_PassabilityMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); | m_HierarchicalPathfinder.Recompute(&m_PassabilityMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
m_LongPathfinder.Update(&m_PassabilityMap); | m_LongPathfinder.Update(&m_PassabilityMap); | ||||
m_HierarchicalPathfinder.Update(&m_PassabilityMap, dirtinessGrid); | m_HierarchicalPathfinder.Update(&m_PassabilityMap, dirtinessGrid); | ||||
} | } | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
if (dimensionChange || justDeserialized) | if (dimensionChange || justDeserialized) | ||||
ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, m_PassabilityMap); | ScriptInterface::ToJSVal(rq, &m_PassabilityMapVal, m_PassabilityMap); | ||||
else | else | ||||
{ | { | ||||
// Avoid a useless memory reallocation followed by a garbage collection. | // Avoid a useless memory reallocation followed by a garbage collection. | ||||
JS::RootedObject mapObj(rq.cx, &m_PassabilityMapVal.toObject()); | JS::RootedObject mapObj(rq.cx, &m_PassabilityMapVal.toObject()); | ||||
JS::RootedValue mapData(rq.cx); | JS::RootedValue mapData(rq.cx); | ||||
ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData)); | ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData)); | ||||
Show All 11 Lines | public: | ||||
void UpdateTerritoryMap(const Grid<u8>& territoryMap) | void UpdateTerritoryMap(const Grid<u8>& territoryMap) | ||||
{ | { | ||||
ENSURE(m_CommandsComputed); | ENSURE(m_CommandsComputed); | ||||
bool dimensionChange = m_TerritoryMap.m_W != territoryMap.m_W || m_TerritoryMap.m_H != territoryMap.m_H; | bool dimensionChange = m_TerritoryMap.m_W != territoryMap.m_W || m_TerritoryMap.m_H != territoryMap.m_H; | ||||
m_TerritoryMap = territoryMap; | m_TerritoryMap = territoryMap; | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
if (dimensionChange) | if (dimensionChange) | ||||
ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, m_TerritoryMap); | ScriptInterface::ToJSVal(rq, &m_TerritoryMapVal, m_TerritoryMap); | ||||
else | else | ||||
{ | { | ||||
// Avoid a useless memory reallocation followed by a garbage collection. | // Avoid a useless memory reallocation followed by a garbage collection. | ||||
JS::RootedObject mapObj(rq.cx, &m_TerritoryMapVal.toObject()); | JS::RootedObject mapObj(rq.cx, &m_TerritoryMapVal.toObject()); | ||||
JS::RootedValue mapData(rq.cx); | JS::RootedValue mapData(rq.cx); | ||||
ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData)); | ENSURE(JS_GetProperty(rq.cx, mapObj, "data", &mapData)); | ||||
Show All 33 Lines | void GetCommands(std::vector<SCommandSets>& commands) | ||||
{ | { | ||||
commands[i].player = m_Players[i]->m_Player; | commands[i].player = m_Players[i]->m_Player; | ||||
commands[i].commands = m_Players[i]->m_Commands; | commands[i].commands = m_Players[i]->m_Commands; | ||||
} | } | ||||
} | } | ||||
void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates) | void LoadEntityTemplates(const std::vector<std::pair<std::string, const CParamNode*> >& templates) | ||||
{ | { | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
m_HasLoadedEntityTemplates = true; | m_HasLoadedEntityTemplates = true; | ||||
ScriptInterface::CreateObject(rq, &m_EntityTemplates); | ScriptInterface::CreateObject(rq, &m_EntityTemplates); | ||||
JS::RootedValue val(rq.cx); | JS::RootedValue val(rq.cx); | ||||
for (size_t i = 0; i < templates.size(); ++i) | for (size_t i = 0; i < templates.size(); ++i) | ||||
{ | { | ||||
Show All 19 Lines | void Serialize(std::ostream& stream, bool isDebug) | ||||
} | } | ||||
} | } | ||||
void SerializeState(ISerializer& serializer) | void SerializeState(ISerializer& serializer) | ||||
{ | { | ||||
if (m_Players.empty()) | if (m_Players.empty()) | ||||
return; | return; | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
std::stringstream rngStream; | std::stringstream rngStream; | ||||
rngStream << m_RNG; | rngStream << m_RNG; | ||||
serializer.StringASCII("rng", rngStream.str(), 0, 32); | serializer.StringASCII("rng", rngStream.str(), 0, 32); | ||||
serializer.NumberU32_Unbounded("turn", m_TurnNum); | serializer.NumberU32_Unbounded("turn", m_TurnNum); | ||||
serializer.Bool("useSharedScript", m_HasSharedComponent); | serializer.Bool("useSharedScript", m_HasSharedComponent); | ||||
▲ Show 20 Lines • Show All 45 Lines • ▼ Show 20 Lines | public: | ||||
void Deserialize(std::istream& stream, u32 numAis) | void Deserialize(std::istream& stream, u32 numAis) | ||||
{ | { | ||||
m_PlayerMetadata.clear(); | m_PlayerMetadata.clear(); | ||||
m_Players.clear(); | m_Players.clear(); | ||||
if (numAis == 0) | if (numAis == 0) | ||||
return; | return; | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad | ENSURE(m_CommandsComputed); // deserializing while we're still actively computing would be bad | ||||
CStdDeserializer deserializer(*m_ScriptInterface, stream); | CStdDeserializer deserializer(*m_ScriptInterface, stream); | ||||
std::string rngString; | std::string rngString; | ||||
std::stringstream rngStream; | std::stringstream rngStream; | ||||
deserializer.StringASCII("rng", rngString, 0, 32); | deserializer.StringASCII("rng", rngString, 0, 32); | ||||
▲ Show 20 Lines • Show All 95 Lines • ▼ Show 20 Lines | if (m_PlayerMetadata.find(path) == m_PlayerMetadata.end()) | ||||
return; | return; | ||||
} | } | ||||
out.set(m_PlayerMetadata[path].get()); | out.set(m_PlayerMetadata[path].get()); | ||||
} | } | ||||
void PerformComputation() | void PerformComputation() | ||||
{ | { | ||||
// Deserialize the game state, to pass to the AI's HandleMessage | // Deserialize the game state, to pass to the AI's HandleMessage | ||||
ScriptInterface::Request rq(m_ScriptInterface); | ScriptRequest rq(m_ScriptInterface); | ||||
JS::RootedValue state(rq.cx); | JS::RootedValue state(rq.cx); | ||||
{ | { | ||||
PROFILE3("AI compute read state"); | PROFILE3("AI compute read state"); | ||||
m_ScriptInterface->ReadStructuredClone(m_GameState, &state); | m_ScriptInterface->ReadStructuredClone(m_GameState, &state); | ||||
m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true); | m_ScriptInterface->SetProperty(state, "passabilityMap", m_PassabilityMapVal, true); | ||||
m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true); | m_ScriptInterface->SetProperty(state, "territoryMap", m_TerritoryMapVal, true); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | public: | ||||
virtual void TryLoadSharedComponent() | virtual void TryLoadSharedComponent() | ||||
{ | { | ||||
m_Worker.TryLoadSharedComponent(); | m_Worker.TryLoadSharedComponent(); | ||||
} | } | ||||
virtual void RunGamestateInit() | virtual void RunGamestateInit() | ||||
{ | { | ||||
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | ||||
ScriptInterface::Request rq(scriptInterface); | ScriptRequest rq(scriptInterface); | ||||
CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity()); | CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity()); | ||||
ENSURE(cmpAIInterface); | ENSURE(cmpAIInterface); | ||||
// Get the game state from AIInterface | // Get the game state from AIInterface | ||||
// We flush events from the initialization so we get a clean state now. | // We flush events from the initialization so we get a clean state now. | ||||
JS::RootedValue state(rq.cx); | JS::RootedValue state(rq.cx); | ||||
cmpAIInterface->GetFullRepresentation(&state, true); | cmpAIInterface->GetFullRepresentation(&state, true); | ||||
Show All 21 Lines | virtual void RunGamestateInit() | ||||
m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state), *passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); | m_Worker.RunGamestateInit(scriptInterface.WriteStructuredClone(state), *passabilityMap, *territoryMap, nonPathfindingPassClassMasks, pathfindingPassClassMasks); | ||||
} | } | ||||
virtual void StartComputation() | virtual void StartComputation() | ||||
{ | { | ||||
PROFILE("AI setup"); | PROFILE("AI setup"); | ||||
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | ||||
ScriptInterface::Request rq(scriptInterface); | ScriptRequest rq(scriptInterface); | ||||
if (m_Worker.getPlayerSize() == 0) | if (m_Worker.getPlayerSize() == 0) | ||||
return; | return; | ||||
CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity()); | CmpPtr<ICmpAIInterface> cmpAIInterface(GetSystemEntity()); | ||||
ENSURE(cmpAIInterface); | ENSURE(cmpAIInterface); | ||||
// Get the game state from AIInterface | // Get the game state from AIInterface | ||||
▲ Show 20 Lines • Show All 47 Lines • ▼ Show 20 Lines | virtual void PushCommands() | ||||
std::vector<CAIWorker::SCommandSets> commands; | std::vector<CAIWorker::SCommandSets> commands; | ||||
m_Worker.GetCommands(commands); | m_Worker.GetCommands(commands); | ||||
CmpPtr<ICmpCommandQueue> cmpCommandQueue(GetSystemEntity()); | CmpPtr<ICmpCommandQueue> cmpCommandQueue(GetSystemEntity()); | ||||
if (!cmpCommandQueue) | if (!cmpCommandQueue) | ||||
return; | return; | ||||
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | ||||
ScriptInterface::Request rq(scriptInterface); | ScriptRequest rq(scriptInterface); | ||||
JS::RootedValue clonedCommandVal(rq.cx); | JS::RootedValue clonedCommandVal(rq.cx); | ||||
for (size_t i = 0; i < commands.size(); ++i) | for (size_t i = 0; i < commands.size(); ++i) | ||||
{ | { | ||||
for (size_t j = 0; j < commands[i].commands.size(); ++j) | for (size_t j = 0; j < commands[i].commands.size(); ++j) | ||||
{ | { | ||||
scriptInterface.ReadStructuredClone(commands[i].commands[j], &clonedCommandVal); | scriptInterface.ReadStructuredClone(commands[i].commands[j], &clonedCommandVal); | ||||
cmpCommandQueue->PushLocalCommand(commands[i].player, clonedCommandVal); | cmpCommandQueue->PushLocalCommand(commands[i].player, clonedCommandVal); | ||||
Show All 34 Lines | private: | ||||
void LoadPathfinderClasses(JS::HandleValue state) | void LoadPathfinderClasses(JS::HandleValue state) | ||||
{ | { | ||||
CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); | CmpPtr<ICmpPathfinder> cmpPathfinder(GetSystemEntity()); | ||||
if (!cmpPathfinder) | if (!cmpPathfinder) | ||||
return; | return; | ||||
const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | const ScriptInterface& scriptInterface = GetSimContext().GetScriptInterface(); | ||||
ScriptInterface::Request rq(scriptInterface); | ScriptRequest rq(scriptInterface); | ||||
JS::RootedValue classesVal(rq.cx); | JS::RootedValue classesVal(rq.cx); | ||||
ScriptInterface::CreateObject(rq, &classesVal); | ScriptInterface::CreateObject(rq, &classesVal); | ||||
std::map<std::string, pass_class_t> classes; | std::map<std::string, pass_class_t> classes; | ||||
cmpPathfinder->GetPassabilityClasses(classes); | cmpPathfinder->GetPassabilityClasses(classes); | ||||
for (std::map<std::string, pass_class_t>::iterator it = classes.begin(); it != classes.end(); ++it) | for (std::map<std::string, pass_class_t>::iterator it = classes.begin(); it != classes.end(); ++it) | ||||
scriptInterface.SetProperty(classesVal, it->first.c_str(), it->second, true); | scriptInterface.SetProperty(classesVal, it->first.c_str(), it->second, true); | ||||
scriptInterface.SetProperty(state, "passabilityClasses", classesVal, true); | scriptInterface.SetProperty(state, "passabilityClasses", classesVal, true); | ||||
} | } | ||||
CAIWorker m_Worker; | CAIWorker m_Worker; | ||||
}; | }; | ||||
REGISTER_COMPONENT_TYPE(AIManager) | REGISTER_COMPONENT_TYPE(AIManager) |
Wildfire Games · Phabricator