18 #include "precompiled.h"
47 #define getpid _getpid // use the non-deprecated function name
50 static std::string
Hexify(
const std::string& s)
52 std::stringstream str;
54 for (
size_t i = 0; i < s.size(); ++i)
55 str << std::setfill(
'0') << std::setw(2) << (int)(
unsigned char)s[i];
85 void ResetState(
bool skipScriptedComponents,
bool skipAI)
118 if (!skipScriptedComponents)
122 #define LOAD_SCRIPTED_COMPONENT(name) \
123 cid = componentManager.LookupCID(name); \
124 if (cid == CID__Invalid) \
125 LOGERROR(L"Can't find component type " L##name); \
126 componentManager.AddComponent(systemEntity, cid, noParam)
136 #undef LOAD_SCRIPTED_COMPONENT
156 void Update(
int turnLength,
const std::vector<SimulationCommand>& commands);
158 void Interpolate(
float simFrameLength,
float frameOffset,
float realFrameLength);
196 const std::vector<SimulationCommand>& commands)
198 std::vector<SimulationCommand> newCommands = commands;
199 for (
size_t i = 0; i < newCommands.size(); ++i)
211 LoadScripts(componentManager, loadedScripts, L
"simulation/components/interfaces/") &&
212 LoadScripts(componentManager, loadedScripts, L
"simulation/helpers/") &&
213 LoadScripts(componentManager, loadedScripts, L
"simulation/components/")
224 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
228 loadedScripts->insert(filename);
259 const double end_time =
timer_Time() + 200e-3;
265 bool progressed =
false;
273 if (!progressed || total == 0)
276 ret =
Clamp(100*progress / total, 1, 100);
285 if (!state.
hash.empty())
291 if (!state.
debug.str().empty())
294 file << state.
debug.str();
297 if (!state.
state.str().empty())
299 std::ofstream file (
OsString(path / (L
"state." + suffix)).c_str(),
std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
300 file << state.
state.str();
312 wunlink(path /
"hash.before.a");
313 wunlink(path /
"hash.before.b");
314 wunlink(path /
"debug.before.a");
315 wunlink(path /
"debug.before.b");
316 wunlink(path /
"state.before.a");
317 wunlink(path /
"state.before.b");
318 wunlink(path /
"hash.after.a");
319 wunlink(path /
"hash.after.b");
320 wunlink(path /
"debug.after.a");
321 wunlink(path /
"debug.after.b");
322 wunlink(path /
"state.after.a");
323 wunlink(path /
"state.after.b");
325 if (primaryStateBefore)
327 if (primaryStateAfter)
329 if (secondaryStateBefore)
331 if (secondaryStateAfter)
354 const bool serializationTestDebugDump =
false;
355 const bool serializationTestHash =
true;
361 if (serializationTestDebugDump)
363 if (serializationTestHash)
376 secondaryContext.
m_Terrain = &secondaryTerrain;
390 if (mapType ==
"random")
393 debug_warn(L
"Serialization test mode only supports scenarios");
397 std::wstring mapFile;
411 if (serializationTestDebugDump)
413 if (serializationTestHash)
416 if (primaryStateBefore.
state.str() != secondaryStateBefore.state.str() ||
417 primaryStateBefore.
hash != secondaryStateBefore.hash)
424 if (serializationTestHash)
432 if (serializationTestHash)
435 if (primaryStateAfter.
state.str() != secondaryStateAfter.
state.str() ||
436 primaryStateAfter.
hash != secondaryStateAfter.
hash)
452 if (m_TurnNumber % 10 == 0)
541 std::stringstream pid;
543 std::stringstream name;\
544 name << std::setw(5) << std::setfill(
'0') <<
m_TurnNumber <<
".txt";
549 file <<
"State hash: " << std::hex;
552 for (
size_t i = 0; i < hashRaw.size(); ++i)
553 file << std::setfill(
'0') << std::setw(2) << (int)(
unsigned char)hashRaw[i];
554 file << std::dec <<
"\n";
660 std::vector<SimulationCommand> commands;
661 m->
Update(turnLength, commands);
666 m->
Update(turnLength, commands);
671 m->
Interpolate(simFrameLength, frameOffset, realFrameLength);
797 std::vector<std::string> data;
803 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
833 std::vector<std::string> data;
839 for (VfsPaths::iterator it = pathnames.begin(); it != pathnames.end(); ++it)
866 return ReadJSON(L
"simulation/data/player_defaults.json");
871 return ReadJSON(L
"simulation/data/map_sizes.json");
907 if (!scriptInterface.
Eval(
"({})", ais) || !scriptInterface.
SetProperty(ais.
get(),
"AIData", aiData))
908 return std::string();
An entity initialisation parameter node.
A simple fixed-point number class.
virtual void FlushTurn(const std::vector< SimulationCommand > &commands)=0
Calls the ProcessCommand(player, cmd) global script function for each command in the local queue and ...
CStr DecodeUTF8() const
Returns contents of a UTF-8 encoded file as a string with optional BOM removed.
CSimulation2(CUnitManager *, CTerrain *)
void FlushDestroyedComponents()
Does the actual destruction of components from DestroyComponentsSoon.
static Status ReloadChangedFileCB(void *param, const VfsPath &path)
void ResetState()
Resets the dynamic simulation state (deletes all entities, resets entity ID counters; doesn't unload/...
void Interpolate(float simFrameLength, float frameOffset, float realFrameLength)
Generic per-turn update message, for things that don't care much about ordering.
std::string ReadJSON(VfsPath path)
const CSimContext & GetSimContext() const
Path VfsPath
VFS path of the form "(dir/)*file?".
static std::string Hexify(const std::string &s)
static std::vector< CScriptValRooted > GetAIs(ScriptInterface &scriptInterface)
Returns a vector of {"id":"value-for-AddPlayer", "name":"Human readable name"} objects, based on all the available AI scripts.
entity_id_t AddEntity(const std::wstring &templateName, entity_id_t ent)
Constructs an entity based on the given template, and adds it the world with entity ID ent...
void SetInitAttributes(const CScriptValRooted &settings)
Set the attributes identifying the scenario/RMS used to initialise this simulation.
IComponent * QueryInterface(entity_id_t ent, int iid) const
virtual void ProcessSameTurnMoves()=0
Process moves during the same turn they were created in to improve responsiveness.
const OsPath & psLogDir()
Status LDR_NonprogressiveLoad()
const PSRETURN PSRETURN_OK
Reads a file, then gives read-only access to the contents.
virtual void FinishAsyncRequests()=0
Finish computing asynchronous path requests and send the CMessagePathResult messages.
bool DeserializeState(std::istream &stream)
IComponent * QueryInterface(entity_id_t ent, InterfaceId iid) const
Add renderable objects to the scene collector.
#define CFG_GET_VAL(name, type, destination)
entity_id_t AddLocalEntity(const std::wstring &templateName)
static void out(const wchar_t *fmt,...)
bool CallFunctionVoid(jsval val, const char *name)
Call the named property on the given object, with void return type and 0 arguments.
Object wrapping an entity_id_t, with a SEntityComponentCache to support fast QueryInterface() / CmpPt...
void Interpolate(float simFrameLength, float frameOffset, float realFrameLength)
std::string m_StartupScript
void Update(int turnLength, const std::vector< SimulationCommand > &commands)
void ResetState(bool skipScriptedComponents=false, bool skipAI=false)
Initialise (or re-initialise) the complete simulation state.
bool m_EnableSerializationTest
ScriptInterface & GetScriptInterface()
A trivial wrapper around a jsval.
std::string GenerateSchema()
Update phase for non-formation-controller unit movement.
void RenderSubmit(SceneCollector &collector, const CFrustum &frustum, bool culling)
bool LoadScript(const VfsPath &filename, const std::string &code)
Load and execute the given script in a new function scope.
T Clamp(T val, T min, T max)
low-level aka "lib"
std::string StringifyJSON(jsval obj, bool indent=true)
Stringify to a JSON string, UTF-8 encoded.
const InterfaceListUnordered & GetEntitiesWithInterfaceUnordered(int iid)
Returns a list of components implementing the given interface, and their associated entities...
Contains pointers to various 'global' objects that are needed by the simulation code, to allow easy access without using real (evil) global variables.
bool SerializeState(std::ostream &stream)
void LoadComponentTypes()
CScriptValRooted ParseJSON(const std::string &string_utf8)
Parse a UTF-8-encoded JSON string.
std::vector< std::string > GetRMSData()
Get random map script data.
bool LoadDefaultScripts()
Call LoadScripts for each of the game's standard simulation script paths.
std::string GetMapSettingsString()
Get the current map settings as a UTF-8 JSON string.
void Update(int turnLength)
float GetLastFrameOffset() const
Returns the last frame offset passed to Interpolate(), i.e.
const entity_id_t SYSTEM_ENTITY
Entity ID for singleton 'system' components.
Status ReloadChangedFile(const VfsPath &path)
Reload any scripts that were loaded from the given filename.
void InitGame(const CScriptVal &data)
Initialise a new game, based on some script data.
This interface accepts renderable objects.
void SetMapSettings(const std::string &settings)
Set the initial map settings (as a UTF-8-encoded JSON string), which will be used to set up the simul...
std::vector< std::pair< entity_id_t, IComponent * > > InterfaceList
const InterfaceListUnordered & GetEntitiesWithInterfaceUnordered(InterfaceId iid) const
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
std::set< VfsPath > m_LoadedScripts
InterfaceList GetEntitiesWithInterface(InterfaceId iid) const
Final update phase, after all other updates.
#define LOAD_SCRIPTED_COMPONENT(name)
static bool LoadScripts(CComponentManager &componentManager, std::set< VfsPath > *loadedScripts, const VfsPath &path)
void UnregisterFileReloadFunc(FileReloadFunc func, void *obj)
delete a callback function registered with RegisterFileReloadFunc (removes any with the same func and...
void BroadcastMessage(const CMessage &msg) const
LIB_API int wunlink(const OsPath &pathname)
void RegisterFileReloadFunc(FileReloadFunc func, void *obj)
register a callback function to be called by ReloadChangedFiles
virtual void PushCommands()=0
Call this at the start of a turn, to push the computed AI commands into the command queue...
const String & string() const
bool ComputeStateHash(std::string &outHash, bool quick)
std::string GetPlayerDefaults()
Get player default data.
ScriptInterface & GetScriptInterface() const
bool Eval(const char *code)
bool LoadScripts(const VfsPath &path)
Load all scripts in the specified directory (non-recursively), so they can register new component typ...
void LoadMap(const VfsPath &pathname, const CScriptValRooted &settings, CTerrain *, WaterManager *, SkyManager *, CLightEnv *, CGameView *, CCinemaManager *, CTriggerManager *, CPostprocManager *pPostproc, CSimulation2 *, const CSimContext *, int playerID, bool skipEntities)
bool ComputeStateHash(std::string &outHash, bool quick)
i64 Status
Error handling system.
static bool IsInitialised()
void InitSystemEntity()
Set up an empty SYSTEM_ENTITY.
std::string GetAIData()
Get AI data.
entity_id_t AllocateNewLocalEntity()
Returns a new local entity ID that has never been used before.
A simplified syntax for accessing entity components.
bool SerializeState(std::ostream &stream)
bool DeserializeState(std::istream &stream)
jsval CloneValueFromOtherContext(ScriptInterface &otherContext, jsval val)
Construct a new value (usable in this ScriptInterface's context) by cloning a value from a different ...
void ReportSerializationFailure(SerializationTestState *primaryStateBefore, SerializationTestState *primaryStateAfter, SerializationTestState *secondaryStateBefore, SerializationTestState *secondaryStateAfter)
const char * GetErrorString(PSRETURN code)
bool GetProperty(jsval obj, const char *name, T &out)
Get the named property on the given object.
virtual void StartComputation()=0
Call this at the end of a turn, to trigger AI computation which will be ready for the next turn...
static CFixed FromInt(int n)
CComponentManager m_ComponentManager
Status ReloadChangedFile(const VfsPath &path)
#define PROFILE2_ATTR
Associates a string (with printf-style formatting) with the current region or event.
void PostMessage(entity_id_t ent, const CMessage &msg) const
Send a message, targeted at a particular entity.
void LoadMapSettings()
Loads the map settings script (called after map is loaded)
bool AddComponent(CEntityHandle ent, ComponentTypeId cid, const CParamNode ¶mNode)
Constructs a component of type 'cid', initialised with data 'paramNode', and attaches it to entity 'e...
bool DumpDebugState(std::ostream &stream, bool includeDebugInfo)
bool LoadScript(const VfsPath &filename, bool hotload=false)
Load a script and execute it in a new function scope.
std::string GetMapSizes()
Get map sizes data.
Path ChangeExtension(Path extension) const
Handle progressive loading of resources.
void ResetState(bool skipScriptedComponents, bool skipAI)
PSRETURN Load(const PIVFS &vfs, const VfsPath &filename)
Returns either PSRETURN_OK or PSRETURN_CVFSFile_LoadFailed.
InterfaceList GetEntitiesWithInterface(int iid)
Returns a list of components implementing the given interface, and their associated entities...
wchar_t * StatusDescription(Status status, wchar_t *buf, size_t max_chars)
generate textual description of a Status.
static std::vector< SimulationCommand > CloneCommandsFromOtherContext(ScriptInterface &oldScript, ScriptInterface &newScript, const std::vector< SimulationCommand > &commands)
void LDR_EndRegistering()
std::vector< std::string > GetCivData()
Get civilization data.
void BroadcastMessage(const CMessage &msg) const
Send a message, not targeted at any particular entity.
CScriptVal GetMapSettings()
Get the current map settings.
void FlushDestroyedEntities()
Does the actual destruction of entities from DestroyEntity.
bool VfsFileExists(const VfsPath &pathname)
CScriptValRooted m_InitAttributes
entity_id_t AddEntity(const std::wstring &templateName)
Construct a new entity and add it to the world.
boost::unordered_map< entity_id_t, IComponent * > InterfaceListUnordered
void DestroyEntity(entity_id_t ent)
Destroys the specified entity, once FlushDestroyedEntities is called.
std::vector< VfsPath > VfsPaths
JSBool error(JSContext *cx, uintN argc, jsval *vp)
std::string GenerateSchema()
jsval get() const
Returns the current value (or JSVAL_VOID if uninitialised).
static void UpdateComponents(CSimContext &simContext, fixed turnLengthFixed, const std::vector< SimulationCommand > &commands)
CEntityHandle GetSystemEntity()
Returns a CEntityHandle with id SYSTEM_ENTITY.
Abstraction around a SpiderMonkey JSContext.
#define debug_warn(expr)
display the error dialog with the given text.
void DestroyComponentsSoon(entity_id_t ent)
Destroys all the components belonging to the specified entity when FlushDestroyedComponents is called...
bool SetProperty(jsval obj, const char *name, const T &value, bool constant=false, bool enumerate=true)
Set the named property on the given object.
int ProgressiveLoad()
RegMemFun incremental loader function.
Prepare for rendering a new frame (set up model positions etc).
CSimulation2Impl(CUnitManager *unitManager, CTerrain *terrain)
Status CreateDirectories(const OsPath &path, mode_t mode)
void SetStartupScript(const std::string &script)
Set a startup script, which will get executed before the first turn.
u32 entity_id_t
Entity ID type.
CUnitManager * m_UnitManager
const std::string & GetStartupScript()
Get the current startup script.
static const player_id_t INVALID_PLAYER
void EnableSerializationTest()
static void ResetComponentState(CComponentManager &componentManager, bool skipScriptedComponents, bool skipAI)
CScriptValRooted GetInitAttributes()
Get the data passed to SetInitAttributes.
Status GetPathnames(const PIVFS &fs, const VfsPath &path, const wchar_t *filter, VfsPaths &pathnames)
bool DumpDebugState(std::ostream &stream)
JSContext * GetContext() const
void MaybeGC()
MaybeGC tries to determine whether garbage collection in cx's runtime would free up enough memory to ...
void DumpSerializationTestState(SerializationTestState &state, const OsPath &path, const OsPath::String &suffix)
void PostMessage(entity_id_t ent, const CMessage &msg) const
static bool LoadDefaultScripts(CComponentManager &componentManager, std::set< VfsPath > *loadedScripts)
CComponentManager & GetComponentManager() const
void LDR_BeginRegistering()
static std::string OsString(const OsPath &path)
void LoadPlayerSettings(bool newPlayers)
Loads the player settings script (called before map is loaded)
entity_id_t AllocateNewEntity()
Returns a new entity ID that has never been used before.
CScriptValRooted m_MapSettings