Changeset View
Changeset View
Standalone View
Standalone View
source/simulation2/Simulation2.cpp
/* Copyright (C) 2021 Wildfire Games. | /* Copyright (C) 2021 Wildfire Games. | ||||
Stan: Bump year.
@Itms: D404 seem to work as expected :) | |||||
Not Done Inline ActionsYear :) Stan: Year :) | |||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 0 A.D. is free software: you can redistribute it and/or modify | ||||
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
Show All 11 Lines | |||||
#include "scriptinterface/ScriptContext.h" | #include "scriptinterface/ScriptContext.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "simulation2/MessageTypes.h" | #include "simulation2/MessageTypes.h" | ||||
#include "simulation2/system/ComponentManager.h" | #include "simulation2/system/ComponentManager.h" | ||||
#include "simulation2/system/ParamNode.h" | #include "simulation2/system/ParamNode.h" | ||||
#include "simulation2/system/SimContext.h" | #include "simulation2/system/SimContext.h" | ||||
#include "simulation2/system/SimSynchronization.h" | |||||
#include "simulation2/components/ICmpAIManager.h" | #include "simulation2/components/ICmpAIManager.h" | ||||
#include "simulation2/components/ICmpCommandQueue.h" | #include "simulation2/components/ICmpCommandQueue.h" | ||||
#include "simulation2/components/ICmpTemplateManager.h" | #include "simulation2/components/ICmpTemplateManager.h" | ||||
#include "graphics/MapReader.h" | #include "graphics/MapReader.h" | ||||
#include "graphics/Terrain.h" | #include "graphics/Terrain.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "lib/file/vfs/vfs_util.h" | #include "lib/file/vfs/vfs_util.h" | ||||
Show All 11 Lines | |||||
#include <iomanip> | #include <iomanip> | ||||
class CSimulation2Impl | class CSimulation2Impl | ||||
{ | { | ||||
public: | public: | ||||
CSimulation2Impl(CUnitManager* unitManager, shared_ptr<ScriptContext> cx, CTerrain* terrain) : | CSimulation2Impl(CUnitManager* unitManager, shared_ptr<ScriptContext> cx, CTerrain* terrain) : | ||||
m_SimContext(), m_ComponentManager(m_SimContext, cx), | m_SimContext(), m_ComponentManager(m_SimContext, cx), | ||||
m_EnableOOSLog(false), m_EnableSerializationTest(false), m_RejoinTestTurn(-1), m_TestingRejoin(false), | m_EnableOOSLog(false), m_EnableSerializationTest(false), m_RejoinTestTurn(-1), m_TestingRejoin(false), | ||||
m_SecondaryTerrain(nullptr), m_SecondaryContext(nullptr), m_SecondaryComponentManager(nullptr), m_SecondaryLoadedScripts(nullptr), | |||||
m_MapSettings(cx->GetGeneralJSContext()), m_InitAttributes(cx->GetGeneralJSContext()) | m_MapSettings(cx->GetGeneralJSContext()), m_InitAttributes(cx->GetGeneralJSContext()) | ||||
{ | { | ||||
m_SimContext.m_SynchronizationData = &m_SynchronizationData; | |||||
m_SimContext.m_UnitManager = unitManager; | m_SimContext.m_UnitManager = unitManager; | ||||
m_SimContext.m_Terrain = terrain; | m_SimContext.m_Terrain = terrain; | ||||
m_ComponentManager.LoadComponentTypes(); | m_ComponentManager.LoadComponentTypes(); | ||||
RegisterFileReloadFunc(ReloadChangedFileCB, this); | RegisterFileReloadFunc(ReloadChangedFileCB, this); | ||||
// Tests won't have config initialised | // Tests won't have config initialised | ||||
if (CConfigDB::IsInitialised()) | if (CConfigDB::IsInitialised()) | ||||
Show All 9 Lines | CSimulation2Impl(CUnitManager* unitManager, shared_ptr<ScriptContext> cx, CTerrain* terrain) : | ||||
{ | { | ||||
m_OOSLogPath = createDateIndexSubdirectory(psLogDir() / "oos_logs"); | m_OOSLogPath = createDateIndexSubdirectory(psLogDir() / "oos_logs"); | ||||
debug_printf("Writing ooslogs to %s\n", m_OOSLogPath.string8().c_str()); | debug_printf("Writing ooslogs to %s\n", m_OOSLogPath.string8().c_str()); | ||||
} | } | ||||
} | } | ||||
~CSimulation2Impl() | ~CSimulation2Impl() | ||||
{ | { | ||||
delete m_SecondaryTerrain; | |||||
delete m_SecondaryContext; | |||||
delete m_SecondaryComponentManager; | |||||
delete m_SecondaryLoadedScripts; | |||||
UnregisterFileReloadFunc(ReloadChangedFileCB, this); | UnregisterFileReloadFunc(ReloadChangedFileCB, this); | ||||
} | } | ||||
void ResetState(bool skipScriptedComponents, bool skipAI) | void ResetState(bool skipScriptedComponents, bool skipAI) | ||||
{ | { | ||||
m_DeltaTime = 0.0; | m_DeltaTime = 0.0; | ||||
m_LastFrameOffset = 0.0f; | m_LastFrameOffset = 0.0f; | ||||
m_TurnNumber = 0; | m_TurnNumber = 0; | ||||
Show All 21 Lines | public: | ||||
void Update(int turnLength, const std::vector<SimulationCommand>& commands); | void Update(int turnLength, const std::vector<SimulationCommand>& commands); | ||||
static void UpdateComponents(CSimContext& simContext, fixed turnLengthFixed, const std::vector<SimulationCommand>& commands); | static void UpdateComponents(CSimContext& simContext, fixed turnLengthFixed, const std::vector<SimulationCommand>& commands); | ||||
void Interpolate(float simFrameLength, float frameOffset, float realFrameLength); | void Interpolate(float simFrameLength, float frameOffset, float realFrameLength); | ||||
void DumpState(); | void DumpState(); | ||||
CSimContext m_SimContext; | CSimContext m_SimContext; | ||||
CComponentManager m_ComponentManager; | CComponentManager m_ComponentManager; | ||||
SSimSynchronization m_SynchronizationData; | |||||
double m_DeltaTime; | double m_DeltaTime; | ||||
float m_LastFrameOffset; | float m_LastFrameOffset; | ||||
std::string m_StartupScript; | std::string m_StartupScript; | ||||
JS::PersistentRootedValue m_InitAttributes; | JS::PersistentRootedValue m_InitAttributes; | ||||
JS::PersistentRootedValue m_MapSettings; | JS::PersistentRootedValue m_MapSettings; | ||||
std::set<VfsPath> m_LoadedScripts; | std::set<VfsPath> m_LoadedScripts; | ||||
uint32_t m_TurnNumber; | uint32_t m_TurnNumber; | ||||
bool m_EnableOOSLog; | bool m_EnableOOSLog; | ||||
OsPath m_OOSLogPath; | OsPath m_OOSLogPath; | ||||
// Functions and data for the serialization test mode: (see Update() for relevant comments) | // Functions and data for the serialization test mode: (see Update() for relevant comments) | ||||
bool m_EnableSerializationTest; | bool m_EnableSerializationTest; | ||||
int m_RejoinTestTurn; | int m_RejoinTestTurn; | ||||
bool m_TestingRejoin; | bool m_TestingRejoin; | ||||
// Secondary simulation | // Secondary simulation (NB: order matters for destruction). | ||||
CTerrain* m_SecondaryTerrain; | std::unique_ptr<SSimSynchronization> m_SecondarySynchronizationData; | ||||
CSimContext* m_SecondaryContext; | std::unique_ptr<CComponentManager> m_SecondaryComponentManager; | ||||
CComponentManager* m_SecondaryComponentManager; | std::unique_ptr<CTerrain> m_SecondaryTerrain; | ||||
std::set<VfsPath>* m_SecondaryLoadedScripts; | std::unique_ptr<CSimContext> m_SecondaryContext; | ||||
std::unique_ptr<std::set<VfsPath>> m_SecondaryLoadedScripts; | |||||
struct SerializationTestState | struct SerializationTestState | ||||
{ | { | ||||
std::stringstream state; | std::stringstream state; | ||||
std::stringstream debug; | std::stringstream debug; | ||||
std::string hash; | std::string hash; | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 240 Lines • ▼ Show 20 Lines | void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationCommand>& commands) | ||||
UpdateComponents(m_SimContext, turnLengthFixed, commands); | UpdateComponents(m_SimContext, turnLengthFixed, commands); | ||||
if (m_EnableSerializationTest || startRejoinTest) | if (m_EnableSerializationTest || startRejoinTest) | ||||
{ | { | ||||
if (startRejoinTest) | if (startRejoinTest) | ||||
debug_printf("Initializing the secondary simulation\n"); | debug_printf("Initializing the secondary simulation\n"); | ||||
delete m_SecondaryTerrain; | m_SecondaryTerrain = std::make_unique<CTerrain>(); | ||||
m_SecondaryTerrain = new CTerrain(); | m_SecondarySynchronizationData = std::make_unique<SSimSynchronization>(); | ||||
delete m_SecondaryContext; | m_SecondaryContext = std::make_unique<CSimContext>(); | ||||
m_SecondaryContext = new CSimContext(); | m_SecondaryContext->m_Terrain = m_SecondaryTerrain.get(); | ||||
m_SecondaryContext->m_Terrain = m_SecondaryTerrain; | m_SecondaryContext->m_SynchronizationData = m_SecondarySynchronizationData.get(); | ||||
delete m_SecondaryComponentManager; | m_SecondaryComponentManager = std::make_unique<CComponentManager>(*m_SecondaryContext, scriptInterface.GetContext()); | ||||
m_SecondaryComponentManager = new CComponentManager(*m_SecondaryContext, scriptInterface.GetContext()); | |||||
m_SecondaryComponentManager->LoadComponentTypes(); | m_SecondaryComponentManager->LoadComponentTypes(); | ||||
delete m_SecondaryLoadedScripts; | m_SecondaryLoadedScripts = std::make_unique<std::set<VfsPath>>(); | ||||
m_SecondaryLoadedScripts = new std::set<VfsPath>(); | ENSURE(LoadDefaultScripts(*m_SecondaryComponentManager, m_SecondaryLoadedScripts.get())); | ||||
ENSURE(LoadDefaultScripts(*m_SecondaryComponentManager, m_SecondaryLoadedScripts)); | |||||
ResetComponentState(*m_SecondaryComponentManager, false, false); | ResetComponentState(*m_SecondaryComponentManager, false, false); | ||||
// Load the trigger scripts after we have loaded the simulation. | // Load the trigger scripts after we have loaded the simulation. | ||||
{ | { | ||||
ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface()); | ScriptRequest rq2(m_SecondaryComponentManager->GetScriptInterface()); | ||||
JS::RootedValue mapSettingsCloned(rq2.cx, | JS::RootedValue mapSettingsCloned(rq2.cx, | ||||
m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, m_MapSettings)); | m_SecondaryComponentManager->GetScriptInterface().CloneValueFromOtherCompartment(scriptInterface, m_MapSettings)); | ||||
ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts)); | ENSURE(LoadTriggerScripts(*m_SecondaryComponentManager, mapSettingsCloned, m_SecondaryLoadedScripts.get())); | ||||
} | } | ||||
// Load the map into the secondary simulation | // Load the map into the secondary simulation | ||||
LDR_BeginRegistering(); | LDR_BeginRegistering(); | ||||
std::unique_ptr<CMapReader> mapReader = std::make_unique<CMapReader>(); | std::unique_ptr<CMapReader> mapReader = std::make_unique<CMapReader>(); | ||||
std::string mapType; | std::string mapType; | ||||
scriptInterface.GetProperty(m_InitAttributes, "mapType", mapType); | scriptInterface.GetProperty(m_InitAttributes, "mapType", mapType); | ||||
if (mapType == "random") | if (mapType == "random") | ||||
{ | { | ||||
// TODO: support random map scripts | // TODO: support random map scripts | ||||
debug_warn(L"Serialization test mode does not support random maps"); | debug_warn(L"Serialization test mode does not support random maps"); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
std::wstring mapFile; | std::wstring mapFile; | ||||
scriptInterface.GetProperty(m_InitAttributes, "map", mapFile); | scriptInterface.GetProperty(m_InitAttributes, "map", mapFile); | ||||
VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp"); | VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp"); | ||||
mapReader->LoadMap(mapfilename, *scriptInterface.GetContext(), JS::UndefinedHandleValue, | mapReader->LoadMap(mapfilename, *scriptInterface.GetContext(), JS::UndefinedHandleValue, | ||||
m_SecondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL, | m_SecondaryTerrain.get(), NULL, NULL, NULL, NULL, NULL, NULL, | ||||
NULL, NULL, m_SecondaryContext, INVALID_PLAYER, true); // throws exception on failure | NULL, NULL, m_SecondaryContext.get(), INVALID_PLAYER, true); // throws exception on failure | ||||
} | } | ||||
LDR_EndRegistering(); | LDR_EndRegistering(); | ||||
ENSURE(LDR_NonprogressiveLoad() == INFO::OK); | ENSURE(LDR_NonprogressiveLoad() == INFO::OK); | ||||
ENSURE(m_SecondaryComponentManager->DeserializeState(primaryStateBefore.state)); | ENSURE(m_SecondaryComponentManager->DeserializeState(primaryStateBefore.state)); | ||||
} | } | ||||
if (m_EnableSerializationTest || m_TestingRejoin) | if (m_EnableSerializationTest || m_TestingRejoin) | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (cmpPathfinder) | ||||
cmpPathfinder->FetchAsyncResultsAndSendMessages(); | cmpPathfinder->FetchAsyncResultsAndSendMessages(); | ||||
{ | { | ||||
PROFILE2("Sim - Update Start"); | PROFILE2("Sim - Update Start"); | ||||
CMessageTurnStart msgTurnStart; | CMessageTurnStart msgTurnStart; | ||||
componentManager.BroadcastMessage(msgTurnStart); | componentManager.BroadcastMessage(msgTurnStart); | ||||
} | } | ||||
// Push AI commands onto the queue before we use them | // Push AI commands onto the queue before we use them | ||||
Done Inline ActionsPut before the grid update because we need to make sure the state isn't changed from last turn. wraitii: Put before the grid update because we need to make sure the state isn't changed from last turn. | |||||
Not Done Inline ActionsMaybe it deserves a comment ? Stan: Maybe it deserves a comment ? | |||||
CmpPtr<ICmpAIManager> cmpAIManager(simContext, SYSTEM_ENTITY); | CmpPtr<ICmpAIManager> cmpAIManager(simContext, SYSTEM_ENTITY); | ||||
if (cmpAIManager) | if (cmpAIManager) | ||||
cmpAIManager->PushCommands(); | cmpAIManager->PushCommands(); | ||||
CmpPtr<ICmpCommandQueue> cmpCommandQueue(simContext, SYSTEM_ENTITY); | CmpPtr<ICmpCommandQueue> cmpCommandQueue(simContext, SYSTEM_ENTITY); | ||||
if (cmpCommandQueue) | if (cmpCommandQueue) | ||||
cmpCommandQueue->FlushTurn(commands); | cmpCommandQueue->FlushTurn(commands); | ||||
// Process newly generated move commands so the UI feels snappy | // Process newly generated move commands so the UI feels snappy | ||||
if (cmpPathfinder) | if (cmpPathfinder) | ||||
{ | { | ||||
Not Done Inline Actions(This is a requirement, so it should be checked in the requirements phase of development, i.e. before the design or implementation stage). elexis: (This is a requirement, so it should be checked in the requirements phase of development, i.e. | |||||
Done Inline ActionsThis comment is outdated since below I call "FetchAsyncResultsAndSendMessages", which actually waits for all paths to be computed, so we aren't running this "during update". It could probably be run during update but I haven't checked and it'd be trickier. wraitii: This comment is outdated since below I call "FetchAsyncResultsAndSendMessages", which actually… | |||||
cmpPathfinder->StartProcessingMoves(true); | cmpPathfinder->StartProcessingMoves(true); | ||||
cmpPathfinder->FetchAsyncResultsAndSendMessages(); | cmpPathfinder->FetchAsyncResultsAndSendMessages(); | ||||
} | } | ||||
// Send all the update phases | // Send all the update phases | ||||
{ | { | ||||
PROFILE2("Sim - Update"); | PROFILE2("Sim - Update"); | ||||
CMessageUpdate msgUpdate(turnLengthFixed); | CMessageUpdate msgUpdate(turnLengthFixed); | ||||
componentManager.BroadcastMessage(msgUpdate); | componentManager.BroadcastMessage(msgUpdate); | ||||
} | } | ||||
Not Done Inline ActionsNuke Stan: Nuke | |||||
Not Done Inline ActionsStill accurate. Stan: Still accurate. | |||||
{ | { | ||||
CMessageUpdate_MotionFormation msgUpdate(turnLengthFixed); | CMessageUpdate_MotionFormation msgUpdate(turnLengthFixed); | ||||
componentManager.BroadcastMessage(msgUpdate); | componentManager.BroadcastMessage(msgUpdate); | ||||
} | } | ||||
// Process move commands for formations (group proxy) | // Process move commands for formations (group proxy) | ||||
if (cmpPathfinder) | if (cmpPathfinder) | ||||
{ | { | ||||
cmpPathfinder->StartProcessingMoves(true); | cmpPathfinder->StartProcessingMoves(true); | ||||
cmpPathfinder->FetchAsyncResultsAndSendMessages(); | cmpPathfinder->FetchAsyncResultsAndSendMessages(); | ||||
} | } | ||||
{ | { | ||||
PROFILE2("Sim - Motion Unit"); | PROFILE2("Sim - Motion Unit"); | ||||
CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed); | CMessageUpdate_MotionUnit msgUpdate(turnLengthFixed); | ||||
componentManager.BroadcastMessage(msgUpdate); | componentManager.BroadcastMessage(msgUpdate); | ||||
} | } | ||||
{ | { | ||||
Not Done Inline ActionsNuke. Stan: Nuke. | |||||
Not Done Inline ActionsHaving blank lines here actually makes sense. If 574 can be blank then why wouldn't there be other blank lines? Kuba386: Having blank lines here actually makes sense. If 574 can be blank then why wouldn't there be… | |||||
PROFILE2("Sim - Update Final"); | PROFILE2("Sim - Update Final"); | ||||
CMessageUpdate_Final msgUpdate(turnLengthFixed); | CMessageUpdate_Final msgUpdate(turnLengthFixed); | ||||
componentManager.BroadcastMessage(msgUpdate); | componentManager.BroadcastMessage(msgUpdate); | ||||
} | } | ||||
// Clean up any entities destroyed during the simulation update | // Clean up any entities destroyed during the simulation update | ||||
componentManager.FlushDestroyedComponents(); | componentManager.FlushDestroyedComponents(); | ||||
// Process all remaining moves | // Process all remaining moves | ||||
Done Inline ActionsComment should be changed to something like "Start processing moves in the background". wraitii: Comment should be changed to something like "Start processing moves in the background". | |||||
if (cmpPathfinder) | if (cmpPathfinder) | ||||
{ | { | ||||
cmpPathfinder->UpdateGrid(); | cmpPathfinder->UpdateGrid(); | ||||
cmpPathfinder->StartProcessingMoves(false); | cmpPathfinder->StartProcessingMoves(false); | ||||
} | } | ||||
} | } | ||||
void CSimulation2Impl::Interpolate(float simFrameLength, float frameOffset, float realFrameLength) | void CSimulation2Impl::Interpolate(float simFrameLength, float frameOffset, float realFrameLength) | ||||
▲ Show 20 Lines • Show All 294 Lines • ▼ Show 20 Lines | |||||
bool CSimulation2::SerializeState(std::ostream& stream) | bool CSimulation2::SerializeState(std::ostream& stream) | ||||
{ | { | ||||
return m->m_ComponentManager.SerializeState(stream); | return m->m_ComponentManager.SerializeState(stream); | ||||
} | } | ||||
bool CSimulation2::DeserializeState(std::istream& stream) | bool CSimulation2::DeserializeState(std::istream& stream) | ||||
{ | { | ||||
m->m_SynchronizationData.Reset(); | |||||
// TODO: need to make sure the required SYSTEM_ENTITY components get constructed | // TODO: need to make sure the required SYSTEM_ENTITY components get constructed | ||||
return m->m_ComponentManager.DeserializeState(stream); | return m->m_ComponentManager.DeserializeState(stream); | ||||
} | } | ||||
void CSimulation2::ActivateRejoinTest(int turn) | void CSimulation2::ActivateRejoinTest(int turn) | ||||
{ | { | ||||
if (m->m_RejoinTestTurn != -1) | if (m->m_RejoinTestTurn != -1) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 98 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator
Bump year.
@Itms: D404 seem to work as expected :)