std::string CSimulation2::GetAIData() { ScriptInterface& scriptInterface = GetScriptInterface(); std::vector<CScriptValRooted> aiData = ICmpAIManager::GetAIs(scriptInterface); // Build single JSON string with array of AI data CScriptValRooted ais; if (!scriptInterface.Eval("({})", ais) || !scriptInterface.SetProperty(ais.get(), "AIData", aiData)) return std::string(); return scriptInterface.StringifyJSON(ais.get()); }
/** * Initializes the game with the set of attributes provided. * Makes calls to initialize the game view, world, and simulation objects. * Calls are made to facilitate progress reporting of the initialization. **/ void CGame::RegisterInit(const CScriptValRooted& attribs, const std::string& savedState) { m_InitialSavedState = savedState; m_IsSavedGame = !savedState.empty(); m_Simulation2->SetInitAttributes(attribs); std::string mapType; m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "mapType", mapType); float speed; if (m_Simulation2->GetScriptInterface().HasProperty(attribs.get(), "gameSpeed") && m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "gameSpeed", speed)) SetSimRate(speed); LDR_BeginRegistering(); RegMemFun(m_Simulation2, &CSimulation2::ProgressiveLoad, L"Simulation init", 1000); // RC, 040804 - GameView needs to be initialized before World, otherwise GameView initialization // overwrites anything stored in the map file that gets loaded by CWorld::Initialize with default // values. At the minute, it's just lighting settings, but could be extended to store camera position. // Storing lighting settings in the game view seems a little odd, but it's no big deal; maybe move it at // some point to be stored in the world object? if (m_GameView) m_GameView->RegisterInit(); if (mapType == "scenario") { // Load scenario attributes std::wstring mapFile; m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "map", mapFile); m_World->RegisterInit(mapFile, m_PlayerID); } else if (mapType == "random") { // Load random map attributes std::wstring scriptFile; CScriptValRooted settings; m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "script", scriptFile); m_Simulation2->GetScriptInterface().GetProperty(attribs.get(), "settings", settings); m_World->RegisterInitRMS(scriptFile, settings, m_PlayerID); } if (m_IsSavedGame) RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000); LDR_EndRegistering(); }
void CGUIManager::DisplayMessageBox(int width, int height, const CStrW& title, const CStrW& message) { // Set up scripted init data for the standard message box window CScriptValRooted data; m_ScriptInterface.Eval("({})", data); m_ScriptInterface.SetProperty(data.get(), "width", width, false); m_ScriptInterface.SetProperty(data.get(), "height", height, false); m_ScriptInterface.SetProperty(data.get(), "mode", 2, false); m_ScriptInterface.SetProperty(data.get(), "title", std::wstring(title), false); m_ScriptInterface.SetProperty(data.get(), "message", std::wstring(message), false); // Display the message box PushPage(L"page_msgbox.xml", data.get()); }
bool Initialise(bool callConstructor) { if (!LoadScripts(m_AIName)) return false; OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; CScriptValRooted metadata = m_Worker.LoadMetadata(path); if (metadata.uninitialised()) { LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str()); return false; } // Get the constructor name from the metadata std::string constructor; if (!m_ScriptInterface.GetProperty(metadata.get(), "constructor", constructor)) { LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); return false; } // Get the constructor function from the loaded scripts CScriptVal ctor; if (!m_ScriptInterface.GetProperty(m_ScriptInterface.GetGlobalObject(), constructor.c_str(), ctor) || ctor.undefined()) { LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } CScriptVal obj; if (callConstructor) { // Set up the data to pass as the constructor argument CScriptVal settings; m_ScriptInterface.Eval(L"({})", settings); m_ScriptInterface.SetProperty(settings.get(), "player", m_Player, false); ENSURE(m_Worker.m_HasLoadedEntityTemplates); m_ScriptInterface.SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); obj = m_ScriptInterface.CallConstructor(ctor.get(), settings.get()); } else { // For deserialization, we want to create the object with the correct prototype // but don't want to actually run the constructor again // XXX: actually we don't currently use this path for deserialization - maybe delete it? obj = m_ScriptInterface.NewObjectFromConstructor(ctor.get()); } if (obj.undefined()) { LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } m_Obj = CScriptValRooted(m_ScriptInterface.GetContext(), obj); return true; }
/** * Handle requests from the GUI for the list of players. * * @return A JS array containing all known players and their presences */ CScriptValRooted XmppClient::GUIGetPlayerList(ScriptInterface& scriptInterface) { std::string presence; CScriptValRooted playerList; scriptInterface.Eval("({})", playerList); for(std::map<std::string, gloox::Presence::PresenceType>::const_iterator it = m_PlayerMap.begin(); it != m_PlayerMap.end(); ++it) { CScriptValRooted player; GetPresenceString(it->second, presence); scriptInterface.Eval("({})", player); scriptInterface.SetProperty(player.get(), "name", wstring_from_utf8(it->first)); scriptInterface.SetProperty(player.get(), "presence", wstring_from_utf8(presence)); scriptInterface.SetProperty(playerList.get(), wstring_from_utf8(it->first).c_str(), player); } return playerList; }
void CMapGeneratorWorker::ExportMap(ScriptInterface::CxPrivate* pCxPrivate, CScriptValRooted data) { CMapGeneratorWorker* self = static_cast<CMapGeneratorWorker*>(pCxPrivate->pCBData); // Copy results CScopeLock lock(self->m_WorkerMutex); self->m_MapData = self->m_ScriptInterface->WriteStructuredClone(data.get()); self->m_Progress = 0; }
/** * Handle requests from the GUI for leaderboard data. * * @return A JS array containing all known leaderboard data */ CScriptValRooted XmppClient::GUIGetBoardList(ScriptInterface& scriptInterface) { CScriptValRooted boardList; scriptInterface.Eval("([])", boardList); for(std::vector<const glooxwrapper::Tag*>::const_iterator it = m_BoardList.begin(); it != m_BoardList.end(); ++it) { CScriptValRooted board; scriptInterface.Eval("({})", board); const char* attributes[] = { "name", "rank", "rating" }; short attributes_length = 3; for (short i = 0; i < attributes_length; i++) scriptInterface.SetProperty(board.get(), attributes[i], wstring_from_utf8((*it)->findAttribute(attributes[i]).to_string())); scriptInterface.CallFunctionVoid(boardList.get(), "push", board); } return boardList; }
/** * Handle requests from the GUI for the list of all active games. * * @return A JS array containing all known games */ CScriptValRooted XmppClient::GUIGetGameList(ScriptInterface& scriptInterface) { CScriptValRooted gameList; scriptInterface.Eval("([])", gameList); for(std::vector<const glooxwrapper::Tag*>::const_iterator it = m_GameList.begin(); it != m_GameList.end(); ++it) { CScriptValRooted game; scriptInterface.Eval("({})", game); const char* stats[] = { "name", "ip", "state", "nbp", "tnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", "victoryCondition" }; short stats_length = 11; for (short i = 0; i < stats_length; i++) scriptInterface.SetProperty(game.get(), stats[i], wstring_from_utf8((*it)->findAttribute(stats[i]).to_string())); scriptInterface.CallFunctionVoid(gameList.get(), "push", game); } return gameList; }
/** * Handle requests from the GUI for the list of players. * * @return A JS array containing all known players and their presences */ CScriptValRooted XmppClient::GUIGetPlayerList(ScriptInterface& scriptInterface) { CScriptValRooted playerList; scriptInterface.Eval("([])", playerList); // Convert the internal data structure to a Javascript object. for (std::map<std::string, std::vector<std::string> >::const_iterator it = m_PlayerMap.begin(); it != m_PlayerMap.end(); ++it) { CScriptValRooted player; scriptInterface.Eval("({})", player); scriptInterface.SetProperty(player.get(), "name", wstring_from_utf8(it->first)); scriptInterface.SetProperty(player.get(), "presence", wstring_from_utf8(it->second[0])); scriptInterface.SetProperty(player.get(), "rating", wstring_from_utf8(it->second[1])); scriptInterface.SetProperty(player.get(), "role", wstring_from_utf8(it->second[2])); scriptInterface.CallFunctionVoid(playerList.get(), "push", player); } return playerList; }
void CMiniMap::FireWorldClickEvent(int button, int clicks) { float x, z; GetMouseWorldCoordinates(x, z); CScriptValRooted coords; g_ScriptingHost.GetScriptInterface().Eval("({})", coords); g_ScriptingHost.GetScriptInterface().SetProperty(coords.get(), "x", x, false); g_ScriptingHost.GetScriptInterface().SetProperty(coords.get(), "z", z, false); ScriptEvent("worldclick", coords); UNUSED2(button); UNUSED2(clicks); }
bool CMapGeneratorWorker::Run() { m_ScriptInterface->SetCallbackData(static_cast<void*> (this)); // Replace RNG with a seeded deterministic function m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG); m_ScriptInterface->LoadGlobalScripts(); // Functions for RMS m_ScriptInterface->RegisterFunction<bool, std::wstring, CMapGeneratorWorker::LoadLibrary>("LoadLibrary"); m_ScriptInterface->RegisterFunction<void, CScriptValRooted, CMapGeneratorWorker::ExportMap>("ExportMap"); m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress"); m_ScriptInterface->RegisterFunction<void, CMapGeneratorWorker::MaybeGC>("MaybeGC"); m_ScriptInterface->RegisterFunction<std::vector<std::string>, CMapGeneratorWorker::GetCivData>("GetCivData"); // Parse settings CScriptValRooted settingsVal = m_ScriptInterface->ParseJSON(m_Settings); if (settingsVal.undefined()) { LOGERROR(L"CMapGeneratorWorker::Run: Failed to parse settings"); return false; } // Init RNG seed uint32_t seed; if (!m_ScriptInterface->GetProperty(settingsVal.get(), "Seed", seed)) { // No seed specified LOGWARNING(L"CMapGeneratorWorker::Run: No seed value specified - using 0"); seed = 0; } m_MapGenRNG.seed((int32_t)seed); // Copy settings to global variable if (!m_ScriptInterface->SetProperty(m_ScriptInterface->GetGlobalObject(), "g_MapSettings", settingsVal)) { LOGERROR(L"CMapGeneratorWorker::Run: Failed to define g_MapSettings"); return false; } // Load RMS LOGMESSAGE(L"Loading RMS '%ls'", m_ScriptPath.string().c_str()); if (!m_ScriptInterface->LoadGlobalScriptFile(m_ScriptPath)) { LOGERROR(L"CMapGeneratorWorker::Run: Failed to load RMS '%ls'", m_ScriptPath.string().c_str()); return false; } return true; }
std::vector<CScriptValRooted> SavedGames::GetSavedGames(ScriptInterface& scriptInterface) { TIMER(L"GetSavedGames"); std::vector<CScriptValRooted> games; Status err; VfsPaths pathnames; err = vfs::GetPathnames(g_VFS, "saves/", L"*.0adsave", pathnames); WARN_IF_ERR(err); for (size_t i = 0; i < pathnames.size(); ++i) { OsPath realPath; err = g_VFS->GetRealPath(pathnames[i], realPath); if (err < 0) { DEBUG_WARN_ERR(err); continue; // skip this file } PIArchiveReader archiveReader = CreateArchiveReader_Zip(realPath); if (!archiveReader) { // Triggered by e.g. the file being open in another program LOGWARNING(L"Failed to read saved game '%ls'", realPath.string().c_str()); continue; // skip this file } CScriptValRooted metadata; CGameLoader loader(scriptInterface, &metadata, NULL); err = archiveReader->ReadEntries(CGameLoader::ReadEntryCallback, (uintptr_t)&loader); if (err < 0) { DEBUG_WARN_ERR(err); continue; // skip this file } CScriptValRooted game; scriptInterface.Eval("({})", game); scriptInterface.SetProperty(game.get(), "id", pathnames[i].Basename()); scriptInterface.SetProperty(game.get(), "metadata", metadata); games.push_back(game); } return games; }
static Status Callback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData) { GetAIsHelper* self = (GetAIsHelper*)cbData; // Extract the 3rd component of the path (i.e. the directory after simulation/ai/) fs::wpath components = pathname.string(); fs::wpath::iterator it = components.begin(); std::advance(it, 2); std::wstring dirname = GetWstringFromWpath(*it); CScriptValRooted ai; self->m_ScriptInterface.Eval("({})", ai); self->m_ScriptInterface.SetProperty(ai.get(), "id", dirname, true); self->m_ScriptInterface.SetProperty(ai.get(), "data", self->m_ScriptInterface.ReadJSONFile(pathname), true); self->m_AIs.push_back(ai); return INFO::OK; }
/** * Send GUI message queue when queried. */ CScriptValRooted XmppClient::GuiPollMessage(ScriptInterface& scriptInterface) { if (m_GuiMessageQueue.empty()) return CScriptValRooted(); GUIMessage message = m_GuiMessageQueue.front(); CScriptValRooted messageVal; scriptInterface.Eval("({})", messageVal); scriptInterface.SetProperty(messageVal.get(), "type", message.type); if (!message.from.empty()) scriptInterface.SetProperty(messageVal.get(), "from", message.from); if (!message.text.empty()) scriptInterface.SetProperty(messageVal.get(), "text", message.text); if (!message.level.empty()) scriptInterface.SetProperty(messageVal.get(), "level", message.level); if (!message.message.empty()) scriptInterface.SetProperty(messageVal.get(), "message", message.message); if (!message.data.empty()) scriptInterface.SetProperty(messageVal.get(), "data", message.data); m_GuiMessageQueue.pop_front(); return messageVal; }
void CComponentManager::Script_RegisterComponentType(void* cbdata, int iid, std::string cname, CScriptVal ctor) { CComponentManager* componentManager = static_cast<CComponentManager*> (cbdata); // Find the C++ component that wraps the interface int cidWrapper = componentManager->GetScriptWrapper(iid); if (cidWrapper == CID__Invalid) { componentManager->m_ScriptInterface.ReportError("Invalid interface id"); return; } const ComponentType& ctWrapper = componentManager->m_ComponentTypesById[cidWrapper]; bool mustReloadComponents = false; // for hotloading ComponentTypeId cid = componentManager->LookupCID(cname); if (cid == CID__Invalid) { // Allocate a new cid number cid = componentManager->m_NextScriptComponentTypeId++; componentManager->m_ComponentTypeIdsByName[cname] = cid; } else { // Component type is already loaded, so do hotloading: if (!componentManager->m_CurrentlyHotloading) { componentManager->m_ScriptInterface.ReportError("Registering component type with already-registered name"); // TODO: report the actual name return; } const ComponentType& ctPrevious = componentManager->m_ComponentTypesById[cid]; // We can only replace scripted component types, not native ones if (ctPrevious.type != CT_Script) { componentManager->m_ScriptInterface.ReportError("Hotloading script component type with same name as native component"); return; } // We don't support changing the IID of a component type (it would require fiddling // around with m_ComponentsByInterface and being careful to guarantee uniqueness per entity) if (ctPrevious.iid != iid) { // ...though it only matters if any components exist with this type if (!componentManager->m_ComponentsByTypeId[cid].empty()) { componentManager->m_ScriptInterface.ReportError("Hotloading script component type mustn't change interface ID"); return; } } // Remove the old component type's message subscriptions std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it; for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it) { std::vector<ComponentTypeId>& types = it->second; std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid); if (ctit != types.end()) types.erase(ctit); } for (it = componentManager->m_GlobalMessageSubscriptions.begin(); it != componentManager->m_GlobalMessageSubscriptions.end(); ++it) { std::vector<ComponentTypeId>& types = it->second; std::vector<ComponentTypeId>::iterator ctit = find(types.begin(), types.end(), cid); if (ctit != types.end()) types.erase(ctit); } mustReloadComponents = true; } std::string schema = "<empty/>"; { CScriptValRooted prototype; if (componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", prototype) && componentManager->m_ScriptInterface.HasProperty(prototype.get(), "Schema")) { componentManager->m_ScriptInterface.GetProperty(prototype.get(), "Schema", schema); } } // Construct a new ComponentType, using the wrapper's alloc functions ComponentType ct = { CT_Script, iid, ctWrapper.alloc, ctWrapper.dealloc, cname, schema, CScriptValRooted(componentManager->m_ScriptInterface.GetContext(), ctor) }; componentManager->m_ComponentTypesById[cid] = ct; componentManager->m_CurrentComponent = cid; // needed by Subscribe // Find all the ctor prototype's On* methods, and subscribe to the appropriate messages: CScriptVal proto; if (!componentManager->m_ScriptInterface.GetProperty(ctor.get(), "prototype", proto)) return; // error std::vector<std::string> methods; if (!componentManager->m_ScriptInterface.EnumeratePropertyNamesWithPrefix(proto.get(), "On", methods)) return; // error for (std::vector<std::string>::const_iterator it = methods.begin(); it != methods.end(); ++it) { std::string name = (*it).substr(2); // strip the "On" prefix // Handle "OnGlobalFoo" functions specially bool isGlobal = false; if (name.substr(0, 6) == "Global") { isGlobal = true; name = name.substr(6); } std::map<std::string, MessageTypeId>::const_iterator mit = componentManager->m_MessageTypeIdsByName.find(name); if (mit == componentManager->m_MessageTypeIdsByName.end()) { std::string msg = "Registered component has unrecognised '" + *it + "' message handler method"; componentManager->m_ScriptInterface.ReportError(msg.c_str()); return; } if (isGlobal) componentManager->SubscribeGloballyToMessageType(mit->second); else componentManager->SubscribeToMessageType(mit->second); } componentManager->m_CurrentComponent = CID__Invalid; if (mustReloadComponents) { // For every script component with this cid, we need to switch its // prototype from the old constructor's prototype property to the new one's const std::map<entity_id_t, IComponent*>& comps = componentManager->m_ComponentsByTypeId[cid]; std::map<entity_id_t, IComponent*>::const_iterator eit = comps.begin(); for (; eit != comps.end(); ++eit) { jsval instance = eit->second->GetJSInstance(); if (!JSVAL_IS_NULL(instance)) componentManager->m_ScriptInterface.SetPrototype(instance, proto.get()); } } }
bool CMapGeneratorWorker::Run() { m_ScriptInterface->SetCallbackData(static_cast<void*> (this)); // Replace RNG with a seeded deterministic function m_ScriptInterface->ReplaceNondeterministicRNG(m_MapGenRNG); m_ScriptInterface->LoadGlobalScripts(); // Functions for RMS m_ScriptInterface->RegisterFunction<bool, std::wstring, CMapGeneratorWorker::LoadLibrary>("LoadLibrary"); m_ScriptInterface->RegisterFunction<void, CScriptValRooted, CMapGeneratorWorker::ExportMap>("ExportMap"); m_ScriptInterface->RegisterFunction<void, int, CMapGeneratorWorker::SetProgress>("SetProgress"); m_ScriptInterface->RegisterFunction<void, CMapGeneratorWorker::MaybeGC>("MaybeGC"); m_ScriptInterface->RegisterFunction<std::vector<std::string>, CMapGeneratorWorker::GetCivData>("GetCivData"); // TODO: This code is a bit ugly because we have to ensure that CScriptValRooted gets destroyed before the ScriptInterface. // In the future we should work more with the standard JSAPI types for rooting on the stack, which should avoid such problems. bool ret = true; { // Parse settings CScriptValRooted settingsVal = m_ScriptInterface->ParseJSON(m_Settings); if (settingsVal.undefined()) { LOGERROR(L"CMapGeneratorWorker::Run: Failed to parse settings"); ret = false; } else { // Init RNG seed u32 seed; if (!m_ScriptInterface->GetProperty(settingsVal.get(), "Seed", seed)) { // No seed specified LOGWARNING(L"CMapGeneratorWorker::Run: No seed value specified - using 0"); seed = 0; } m_MapGenRNG.seed(seed); // Copy settings to global variable if (!m_ScriptInterface->SetProperty(m_ScriptInterface->GetGlobalObject(), "g_MapSettings", settingsVal)) { LOGERROR(L"CMapGeneratorWorker::Run: Failed to define g_MapSettings"); ret = false; } else { // Load RMS LOGMESSAGE(L"Loading RMS '%ls'", m_ScriptPath.string().c_str()); if (!m_ScriptInterface->LoadGlobalScriptFile(m_ScriptPath)) { LOGERROR(L"CMapGeneratorWorker::Run: Failed to load RMS '%ls'", m_ScriptPath.string().c_str()); ret = false; } } } } // We must destroy the ScriptInterface in the same thread because the JSAPI requires that! SAFE_DELETE(m_ScriptInterface); return ret; }
void CNetClientTurnManager::PostCommand(CScriptValRooted data) { NETTURN_LOG((L"PostCommand()\n")); // Transmit command to server CSimulationMessage msg(m_Simulation2.GetScriptInterface(), m_ClientId, m_PlayerId, m_CurrentTurn + COMMAND_DELAY, data.get()); m_NetClient.SendMessage(&msg); // Add to our local queue //AddCommand(m_ClientId, m_PlayerId, data, m_CurrentTurn + COMMAND_DELAY); // TODO: we should do this when the server stops sending our commands back to us }
bool Initialise(bool callConstructor) { // LoadScripts will only load each script once even though we call it for each player if (!m_Worker.LoadScripts(m_AIName)) return false; OsPath path = L"simulation/ai/" + m_AIName + L"/data.json"; CScriptValRooted metadata = m_Worker.LoadMetadata(path); if (metadata.uninitialised()) { LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str()); return false; } // Get the constructor name from the metadata // If the AI doesn't use modules, we look for the constructor in the global object // TODO: All AIs should use modules. Remove the condition if this requirement is met. std::string moduleName; std::string constructor; CScriptVal objectWithConstructor; // object that should contain the constructor function CScriptVal ctor; if (!m_ScriptInterface->HasProperty(metadata.get(), "moduleName")) { objectWithConstructor = m_ScriptInterface->GetGlobalObject(); } else { m_ScriptInterface->GetProperty(metadata.get(), "moduleName", moduleName); if(!m_ScriptInterface->GetProperty(m_ScriptInterface->GetGlobalObject(), moduleName.c_str(), objectWithConstructor) || objectWithConstructor.undefined()) { LOGERROR(L"Failed to create AI player: %ls: can't find the module that should contain the constructor: '%hs'", path.string().c_str(), moduleName.c_str()); return false; } } if (!m_ScriptInterface->GetProperty(metadata.get(), "constructor", constructor)) { LOGERROR(L"Failed to create AI player: %ls: missing 'constructor'", path.string().c_str()); return false; } // Get the constructor function from the loaded scripts if (!m_ScriptInterface->GetProperty(objectWithConstructor.get(), constructor.c_str(), ctor) || ctor.undefined()) { LOGERROR(L"Failed to create AI player: %ls: can't find constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } m_ScriptInterface->GetProperty(metadata.get(), "useShared", m_UseSharedComponent); CScriptVal obj; if (callConstructor) { // Set up the data to pass as the constructor argument CScriptVal settings; m_ScriptInterface->Eval(L"({})", settings); m_ScriptInterface->SetProperty(settings.get(), "player", m_Player, false); m_ScriptInterface->SetProperty(settings.get(), "difficulty", m_Difficulty, false); ENSURE(m_Worker.m_HasLoadedEntityTemplates); m_ScriptInterface->SetProperty(settings.get(), "templates", m_Worker.m_EntityTemplates, false); obj = m_ScriptInterface->CallConstructor(ctor.get(), settings.get()); } else { // For deserialization, we want to create the object with the correct prototype // but don't want to actually run the constructor again // XXX: actually we don't currently use this path for deserialization - maybe delete it? obj = m_ScriptInterface->NewObjectFromConstructor(ctor.get()); } if (obj.undefined()) { LOGERROR(L"Failed to create AI player: %ls: error calling constructor '%hs'", path.string().c_str(), constructor.c_str()); return false; } m_Obj = CScriptValRooted(m_ScriptInterface->GetContext(), obj); return true; }
template<> jsval ScriptInterface::ToJSVal<CScriptValRooted>(JSContext* UNUSED(cx), const CScriptValRooted& val) { return val.get(); }
void InitGraphics(const CmdLineArgs& args, int flags) { const bool setup_vmode = (flags & INIT_HAVE_VMODE) == 0; if(setup_vmode) { InitSDL(); if (!g_VideoMode.InitSDL()) throw PSERROR_System_VmodeFailed(); // abort startup #if !SDL_VERSION_ATLEAST(2, 0, 0) SDL_WM_SetCaption("0 A.D.", "0 A.D."); #endif } RunHardwareDetection(); tex_codec_register_all(); const int quality = SANE_TEX_QUALITY_DEFAULT; // TODO: set value from config file SetTextureQuality(quality); ogl_WarnIfError(); // Optionally start profiler GPU timings automatically // (By default it's only enabled by a hotkey, for performance/compatibility) bool profilerGPUEnable = false; CFG_GET_VAL("profiler2.gpu.autoenable", Bool, profilerGPUEnable); if (profilerGPUEnable) g_Profiler2.EnableGPU(); if(!g_Quickstart) { WriteSystemInfo(); // note: no longer vfs_display here. it's dog-slow due to unbuffered // file output and very rarely needed. } if(g_DisableAudio) { // speed up startup by disabling all sound // (OpenAL init will be skipped). // must be called before first snd_open. #if CONFIG2_AUDIO CSoundManager::SetEnabled(false); #endif } g_GUI = new CGUIManager(g_ScriptingHost.GetScriptInterface()); // (must come after SetVideoMode, since it calls ogl_Init) const char* missing = ogl_HaveExtensions(0, "GL_ARB_multitexture", "GL_EXT_draw_range_elements", "GL_ARB_texture_env_combine", "GL_ARB_texture_env_dot3", NULL); if(missing) { wchar_t buf[500]; swprintf_s(buf, ARRAY_SIZE(buf), L"The %hs extension doesn't appear to be available on your computer." L" The game may still work, though - you are welcome to try at your own risk." L" If not or it doesn't look right, upgrade your graphics card.", missing ); DEBUG_DISPLAY_ERROR(buf); // TODO: i18n } if (!ogl_HaveExtension("GL_ARB_texture_env_crossbar")) { DEBUG_DISPLAY_ERROR( L"The GL_ARB_texture_env_crossbar extension doesn't appear to be available on your computer." L" Shadows are not available and overall graphics quality might suffer." L" You are advised to try installing newer drivers and/or upgrade your graphics card."); g_Shadows = false; } ogl_WarnIfError(); InitRenderer(); InitInput(); ogl_WarnIfError(); try { if (!Autostart(args)) { const bool setup_gui = ((flags & INIT_NO_GUI) == 0); // We only want to display the splash screen at startup CScriptValRooted data; if (g_GUI) { ScriptInterface& scriptInterface = g_GUI->GetScriptInterface(); scriptInterface.Eval("({})", data); scriptInterface.SetProperty(data.get(), "isStartup", true); } InitPs(setup_gui, L"page_pregame.xml", data.get()); } } catch (PSERROR_Game_World_MapLoadFailed e) { // Map Loading failed // Start the engine so we have a GUI InitPs(true, L"page_pregame.xml", JSVAL_VOID); // Call script function to do the actual work // (delete game data, switch GUI page, show error, etc.) CancelLoad(CStr(e.what()).FromUTF8()); } }
void RunHardwareDetection() { TIMER(L"RunHardwareDetection"); ScriptInterface& scriptInterface = g_ScriptingHost.GetScriptInterface(); scriptInterface.RegisterFunction<void, bool, &SetDisableAudio>("SetDisableAudio"); scriptInterface.RegisterFunction<void, bool, &SetDisableS3TC>("SetDisableS3TC"); scriptInterface.RegisterFunction<void, bool, &SetDisableShadows>("SetDisableShadows"); scriptInterface.RegisterFunction<void, bool, &SetDisableShadowPCF>("SetDisableShadowPCF"); scriptInterface.RegisterFunction<void, bool, &SetDisableAllWater>("SetDisableAllWater"); scriptInterface.RegisterFunction<void, bool, &SetDisableFancyWater>("SetDisableFancyWater"); scriptInterface.RegisterFunction<void, bool, &SetDisableFBOWater>("SetDisableFBOWater"); scriptInterface.RegisterFunction<void, std::string, &SetRenderPath>("SetRenderPath"); // Load the detection script: const wchar_t* scriptName = L"hwdetect/hwdetect.js"; CVFSFile file; if (file.Load(g_VFS, scriptName) != PSRETURN_OK) { LOGERROR(L"Failed to load hardware detection script"); return; } std::string code = file.DecodeUTF8(); // assume it's UTF-8 scriptInterface.LoadScript(scriptName, code); // Collect all the settings we'll pass to the script: // (We'll use this same data for the opt-in online reporting system, so it // includes some fields that aren't directly useful for the hwdetect script) CScriptValRooted settings; scriptInterface.Eval("({})", settings); scriptInterface.SetProperty(settings.get(), "os_unix", OS_UNIX); scriptInterface.SetProperty(settings.get(), "os_bsd", OS_BSD); scriptInterface.SetProperty(settings.get(), "os_linux", OS_LINUX); scriptInterface.SetProperty(settings.get(), "os_android", OS_ANDROID); scriptInterface.SetProperty(settings.get(), "os_macosx", OS_MACOSX); scriptInterface.SetProperty(settings.get(), "os_win", OS_WIN); scriptInterface.SetProperty(settings.get(), "arch_ia32", ARCH_IA32); scriptInterface.SetProperty(settings.get(), "arch_amd64", ARCH_AMD64); scriptInterface.SetProperty(settings.get(), "arch_arm", ARCH_ARM); #ifdef NDEBUG scriptInterface.SetProperty(settings.get(), "build_debug", 0); #else scriptInterface.SetProperty(settings.get(), "build_debug", 1); #endif scriptInterface.SetProperty(settings.get(), "build_opengles", CONFIG2_GLES); scriptInterface.SetProperty(settings.get(), "build_datetime", std::string(__DATE__ " " __TIME__)); scriptInterface.SetProperty(settings.get(), "build_revision", std::wstring(svn_revision)); scriptInterface.SetProperty(settings.get(), "build_msc", (int)MSC_VERSION); scriptInterface.SetProperty(settings.get(), "build_icc", (int)ICC_VERSION); scriptInterface.SetProperty(settings.get(), "build_gcc", (int)GCC_VERSION); scriptInterface.SetProperty(settings.get(), "build_clang", (int)CLANG_VERSION); scriptInterface.SetProperty(settings.get(), "gfx_card", gfx::CardName()); scriptInterface.SetProperty(settings.get(), "gfx_drv_ver", gfx::DriverInfo()); scriptInterface.SetProperty(settings.get(), "snd_card", std::wstring(snd_card)); scriptInterface.SetProperty(settings.get(), "snd_drv_ver", std::wstring(snd_drv_ver)); ReportGLLimits(scriptInterface, settings); scriptInterface.SetProperty(settings.get(), "video_xres", g_VideoMode.GetXRes()); scriptInterface.SetProperty(settings.get(), "video_yres", g_VideoMode.GetYRes()); scriptInterface.SetProperty(settings.get(), "video_bpp", g_VideoMode.GetBPP()); scriptInterface.SetProperty(settings.get(), "video_desktop_xres", g_VideoMode.GetDesktopXRes()); scriptInterface.SetProperty(settings.get(), "video_desktop_yres", g_VideoMode.GetDesktopYRes()); scriptInterface.SetProperty(settings.get(), "video_desktop_bpp", g_VideoMode.GetDesktopBPP()); scriptInterface.SetProperty(settings.get(), "video_desktop_freq", g_VideoMode.GetDesktopFreq()); struct utsname un; uname(&un); scriptInterface.SetProperty(settings.get(), "uname_sysname", std::string(un.sysname)); scriptInterface.SetProperty(settings.get(), "uname_release", std::string(un.release)); scriptInterface.SetProperty(settings.get(), "uname_version", std::string(un.version)); scriptInterface.SetProperty(settings.get(), "uname_machine", std::string(un.machine)); #if OS_LINUX { std::ifstream ifs("/etc/lsb-release"); if (ifs.good()) { std::string str((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); scriptInterface.SetProperty(settings.get(), "linux_release", str); } } #endif scriptInterface.SetProperty(settings.get(), "cpu_identifier", std::string(cpu_IdentifierString())); scriptInterface.SetProperty(settings.get(), "cpu_frequency", os_cpu_ClockFrequency()); scriptInterface.SetProperty(settings.get(), "cpu_pagesize", (u32)os_cpu_PageSize()); scriptInterface.SetProperty(settings.get(), "cpu_largepagesize", (u32)os_cpu_LargePageSize()); scriptInterface.SetProperty(settings.get(), "cpu_numprocs", (u32)os_cpu_NumProcessors()); #if ARCH_X86_X64 scriptInterface.SetProperty(settings.get(), "cpu_numpackages", (u32)topology::NumPackages()); scriptInterface.SetProperty(settings.get(), "cpu_coresperpackage", (u32)topology::CoresPerPackage()); scriptInterface.SetProperty(settings.get(), "cpu_logicalpercore", (u32)topology::LogicalPerCore()); scriptInterface.SetProperty(settings.get(), "cpu_numcaches", (u32)topology::NumCaches()); #endif scriptInterface.SetProperty(settings.get(), "numa_numnodes", (u32)numa_NumNodes()); scriptInterface.SetProperty(settings.get(), "numa_factor", numa_Factor()); scriptInterface.SetProperty(settings.get(), "numa_interleaved", numa_IsMemoryInterleaved()); scriptInterface.SetProperty(settings.get(), "ram_total", (u32)os_cpu_MemorySize()); scriptInterface.SetProperty(settings.get(), "ram_total_os", (u32)os_cpu_QueryMemorySize()); scriptInterface.SetProperty(settings.get(), "ram_free", (u32)os_cpu_MemoryAvailable()); #if ARCH_X86_X64 scriptInterface.SetProperty(settings.get(), "x86_frequency", x86_x64::ClockFrequency()); scriptInterface.SetProperty(settings.get(), "x86_vendor", (u32)x86_x64::Vendor()); scriptInterface.SetProperty(settings.get(), "x86_model", (u32)x86_x64::Model()); scriptInterface.SetProperty(settings.get(), "x86_family", (u32)x86_x64::Family()); u32 caps0, caps1, caps2, caps3; x86_x64::GetCapBits(&caps0, &caps1, &caps2, &caps3); scriptInterface.SetProperty(settings.get(), "x86_caps[0]", caps0); scriptInterface.SetProperty(settings.get(), "x86_caps[1]", caps1); scriptInterface.SetProperty(settings.get(), "x86_caps[2]", caps2); scriptInterface.SetProperty(settings.get(), "x86_caps[3]", caps3); scriptInterface.SetProperty(settings.get(), "x86_icaches", ConvertCaches(scriptInterface, x86_x64::L1I)); scriptInterface.SetProperty(settings.get(), "x86_dcaches", ConvertCaches(scriptInterface, x86_x64::L1D)); scriptInterface.SetProperty(settings.get(), "x86_tlbs", ConvertTLBs(scriptInterface)); #endif scriptInterface.SetProperty(settings.get(), "timer_resolution", timer_Resolution()); // Send the same data to the reporting system g_UserReporter.SubmitReport("hwdetect", 11, scriptInterface.StringifyJSON(settings.get(), false)); // Run the detection script: scriptInterface.CallFunctionVoid(scriptInterface.GetGlobalObject(), "RunHardwareDetection", settings); }
bool Autostart(const CmdLineArgs& args) { /* * Handle various command-line options, for quick testing of various features: * -autostart=name -- map name for scenario, or rms name for random map * -autostart-ai=1:dummybot -- adds the dummybot AI to player 1 * -autostart-playername=name -- multiplayer player name * -autostart-host -- multiplayer host mode * -autostart-players=2 -- number of players * -autostart-client -- multiplayer client mode * -autostart-ip=127.0.0.1 -- multiplayer connect to 127.0.0.1 * -autostart-random=104 -- random map, optional seed value = 104 (default is 0, random is -1) * -autostart-size=192 -- random map size in tiles = 192 (default is 192) * * Examples: * -autostart=Acropolis -autostart-host -autostart-players=2 -- Host game on Acropolis map, 2 players * -autostart=latium -autostart-random=-1 -- Start single player game on latium random map, random rng seed */ CStr autoStartName = args.Get("autostart"); #if OS_ANDROID // HACK: currently the most convenient way to test maps on Android; // should find a better solution autoStartName = "Oasis"; #endif if (autoStartName.empty()) { return false; } g_Game = new CGame(); ScriptInterface& scriptInterface = g_Game->GetSimulation2()->GetScriptInterface(); CScriptValRooted attrs; scriptInterface.Eval("({})", attrs); CScriptVal settings; scriptInterface.Eval("({})", settings); CScriptVal playerData; scriptInterface.Eval("([])", playerData); // Set different attributes for random or scenario game if (args.Has("autostart-random")) { CStr seedArg = args.Get("autostart-random"); // Default seed is 0 uint32 seed = 0; if (!seedArg.empty()) { if (seedArg.compare("-1") == 0) { // Random seed value seed = rand(); } else { seed = seedArg.ToULong(); } } // Random map definition will be loaded from JSON file, so we need to parse it std::wstring mapPath = L"maps/random/"; std::wstring scriptPath = mapPath + autoStartName.FromUTF8() + L".json"; CScriptValRooted scriptData = scriptInterface.ReadJSONFile(scriptPath); if (!scriptData.undefined() && scriptInterface.GetProperty(scriptData.get(), "settings", settings)) { // JSON loaded ok - copy script name over to game attributes std::wstring scriptFile; scriptInterface.GetProperty(settings.get(), "Script", scriptFile); scriptInterface.SetProperty(attrs.get(), "script", scriptFile); // RMS filename } else { // Problem with JSON file LOGERROR(L"Error reading random map script '%ls'", scriptPath.c_str()); throw PSERROR_Game_World_MapLoadFailed("Error reading random map script.\nCheck application log for details."); } // Get optional map size argument (default 192) uint mapSize = 192; if (args.Has("autostart-size")) { CStr size = args.Get("autostart-size"); mapSize = size.ToUInt(); } scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName)); scriptInterface.SetProperty(attrs.get(), "mapPath", mapPath); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("random")); scriptInterface.SetProperty(settings.get(), "Seed", seed); // Random seed scriptInterface.SetProperty(settings.get(), "Size", mapSize); // Random map size (in patches) // Get optional number of players (default 2) size_t numPlayers = 2; if (args.Has("autostart-players")) { CStr num = args.Get("autostart-players"); numPlayers = num.ToUInt(); } // Set up player data for (size_t i = 0; i < numPlayers; ++i) { CScriptVal player; scriptInterface.Eval("({})", player); // We could load player_defaults.json here, but that would complicate the logic // even more and autostart is only intended for developers anyway scriptInterface.SetProperty(player.get(), "Civ", std::string("athen")); scriptInterface.SetPropertyInt(playerData.get(), i, player); } } else { scriptInterface.SetProperty(attrs.get(), "map", std::string(autoStartName)); scriptInterface.SetProperty(attrs.get(), "mapType", std::string("scenario")); } // Set player data for AIs // attrs.settings = { PlayerData: [ { AI: ... }, ... ] }: if (args.Has("autostart-ai")) { std::vector<CStr> aiArgs = args.GetMultiple("autostart-ai"); for (size_t i = 0; i < aiArgs.size(); ++i) { // Instead of overwriting existing player data, modify the array CScriptVal player; if (!scriptInterface.GetPropertyInt(playerData.get(), i, player) || player.undefined()) { scriptInterface.Eval("({})", player); } int playerID = aiArgs[i].BeforeFirst(":").ToInt(); CStr name = aiArgs[i].AfterFirst(":"); scriptInterface.SetProperty(player.get(), "AI", std::string(name)); scriptInterface.SetPropertyInt(playerData.get(), playerID-1, player); } } // Add player data to map settings scriptInterface.SetProperty(settings.get(), "PlayerData", playerData); // Add map settings to game attributes scriptInterface.SetProperty(attrs.get(), "settings", settings); CScriptVal mpInitData; g_GUI->GetScriptInterface().Eval("({isNetworked:true, playerAssignments:{}})", mpInitData); g_GUI->GetScriptInterface().SetProperty(mpInitData.get(), "attribs", CScriptVal(g_GUI->GetScriptInterface().CloneValueFromOtherContext(scriptInterface, attrs.get()))); // Get optional playername CStrW userName = L"anonymous"; if (args.Has("autostart-playername")) { userName = args.Get("autostart-playername").FromUTF8(); } if (args.Has("autostart-host")) { InitPs(true, L"page_loading.xml", mpInitData.get()); size_t maxPlayers = 2; if (args.Has("autostart-players")) { maxPlayers = args.Get("autostart-players").ToUInt(); } g_NetServer = new CNetServer(maxPlayers); g_NetServer->UpdateGameAttributes(attrs.get(), scriptInterface); bool ok = g_NetServer->SetupConnection(); ENSURE(ok); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); g_NetClient->SetupConnection("127.0.0.1"); } else if (args.Has("autostart-client")) { InitPs(true, L"page_loading.xml", mpInitData.get()); g_NetClient = new CNetClient(g_Game); g_NetClient->SetUserName(userName); CStr ip = "127.0.0.1"; if (args.Has("autostart-ip")) { ip = args.Get("autostart-ip"); } bool ok = g_NetClient->SetupConnection(ip); ENSURE(ok); } else { g_Game->SetPlayerID(1); g_Game->StartGame(attrs, ""); LDR_NonprogressiveLoad(); PSRETURN ret = g_Game->ReallyStartGame(); ENSURE(ret == PSRETURN_OK); InitPs(true, L"page_session.xml", JSVAL_VOID); } return true; }
Status SavedGames::Save(const std::wstring& prefix, CSimulation2& simulation, CGUIManager* gui, int playerID) { // Determine the filename to save under const VfsPath basenameFormat(L"saves/" + prefix + L"-%04d"); const VfsPath filenameFormat = basenameFormat.ChangeExtension(L".0adsave"); VfsPath filename; // Don't make this a static global like NextNumberedFilename expects, because // that wouldn't work when 'prefix' changes, and because it's not thread-safe size_t nextSaveNumber = 0; vfs::NextNumberedFilename(g_VFS, filenameFormat, nextSaveNumber, filename); // ArchiveWriter_Zip can only write to OsPaths, not VfsPaths, // but we'd like to handle saved games via VFS. // To avoid potential confusion from writing with non-VFS then // reading the same file with VFS, we'll just write to a temporary // non-VFS path and then load and save again via VFS, // which is kind of a hack. OsPath tempSaveFileRealPath; WARN_RETURN_STATUS_IF_ERR(g_VFS->GetDirectoryRealPath("cache/", tempSaveFileRealPath)); tempSaveFileRealPath = tempSaveFileRealPath / "temp.0adsave"; time_t now = time(NULL); // Construct the serialized state to be saved std::stringstream simStateStream; if (!simulation.SerializeState(simStateStream)) WARN_RETURN(ERR::FAIL); CScriptValRooted metadata; simulation.GetScriptInterface().Eval("({})", metadata); simulation.GetScriptInterface().SetProperty(metadata.get(), "version_major", SAVED_GAME_VERSION_MAJOR); simulation.GetScriptInterface().SetProperty(metadata.get(), "version_minor", SAVED_GAME_VERSION_MINOR); simulation.GetScriptInterface().SetProperty(metadata.get(), "time", (double)now); simulation.GetScriptInterface().SetProperty(metadata.get(), "player", playerID); simulation.GetScriptInterface().SetProperty(metadata.get(), "initAttributes", simulation.GetInitAttributes()); if (gui) { CScriptVal guiMetadata = simulation.GetScriptInterface().CloneValueFromOtherContext(gui->GetScriptInterface(), gui->GetSavedGameData().get()); simulation.GetScriptInterface().SetProperty(metadata.get(), "gui", guiMetadata); } std::string metadataString = simulation.GetScriptInterface().StringifyJSON(metadata.get(), true); // Write the saved game as zip file containing the various components PIArchiveWriter archiveWriter = CreateArchiveWriter_Zip(tempSaveFileRealPath, false); if (!archiveWriter) WARN_RETURN(ERR::FAIL); WARN_RETURN_STATUS_IF_ERR(archiveWriter->AddMemory((const u8*)metadataString.c_str(), metadataString.length(), now, "metadata.json")); WARN_RETURN_STATUS_IF_ERR(archiveWriter->AddMemory((const u8*)simStateStream.str().c_str(), simStateStream.str().length(), now, "simulation.dat")); archiveWriter.reset(); // close the file WriteBuffer buffer; FileInfo tempSaveFile; WARN_RETURN_STATUS_IF_ERR(GetFileInfo(tempSaveFileRealPath, &tempSaveFile)); buffer.Reserve(tempSaveFile.Size()); WARN_RETURN_STATUS_IF_ERR(io::Load(tempSaveFileRealPath, buffer.Data().get(), buffer.Size())); WARN_RETURN_STATUS_IF_ERR(g_VFS->CreateFile(filename, buffer.Data(), buffer.Size())); OsPath realPath; WARN_RETURN_STATUS_IF_ERR(g_VFS->GetRealPath(filename, realPath)); LOGMESSAGERENDER(L"Saved game to %ls\n", realPath.string().c_str()); return INFO::OK; }
static void PostCommand(void* cbdata, CScriptValRooted cmd) { CAIPlayer* self = static_cast<CAIPlayer*> (cbdata); self->m_Commands.push_back(self->m_ScriptInterface.WriteStructuredClone(cmd.get())); }
void CReplayLogger::StartGame(const CScriptValRooted& attribs) { *m_Stream << "start " << m_ScriptInterface.StringifyJSON(attribs.get(), false) << "\n"; }
void CSimulation2Impl::Update(int turnLength, const std::vector<SimulationCommand>& commands) { PROFILE3("sim update"); PROFILE2_ATTR("turn %d", (int)m_TurnNumber); fixed turnLengthFixed = fixed::FromInt(turnLength) / 1000; /* * In serialization test mode, we save the original (primary) simulation state before each turn update. * We run the update, then load the saved state into a secondary context. * We serialize that again and compare to the original serialization (to check that * serialize->deserialize->serialize is equivalent to serialize). * Then we run the update on the secondary context, and check that its new serialized * state matches the primary context after the update (to check that the simulation doesn't depend * on anything that's not serialized). */ const bool serializationTestDebugDump = false; // set true to save human-readable state dumps before an error is detected, for debugging (but slow) const bool serializationTestHash = true; // set true to save and compare hash of state SerializationTestState primaryStateBefore; if (m_EnableSerializationTest) { ENSURE(m_ComponentManager.SerializeState(primaryStateBefore.state)); if (serializationTestDebugDump) ENSURE(m_ComponentManager.DumpDebugState(primaryStateBefore.debug, false)); if (serializationTestHash) ENSURE(m_ComponentManager.ComputeStateHash(primaryStateBefore.hash, false)); } UpdateComponents(m_SimContext, turnLengthFixed, commands); if (m_EnableSerializationTest) { // Initialise the secondary simulation CTerrain secondaryTerrain; CSimContext secondaryContext; secondaryContext.m_Terrain = &secondaryTerrain; CComponentManager secondaryComponentManager(secondaryContext, m_ComponentManager.GetScriptInterface().GetRuntime()); secondaryComponentManager.LoadComponentTypes(); ENSURE(LoadDefaultScripts(secondaryComponentManager, NULL)); ResetComponentState(secondaryComponentManager, false, false); // Load the map into the secondary simulation LDR_BeginRegistering(); CMapReader* mapReader = new CMapReader; // automatically deletes itself // TODO: this duplicates CWorld::RegisterInit and could probably be cleaned up a bit std::string mapType; m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "mapType", mapType); if (mapType == "random") { // TODO: support random map scripts debug_warn(L"Serialization test mode only supports scenarios"); } else { std::wstring mapFile; m_ComponentManager.GetScriptInterface().GetProperty(m_InitAttributes.get(), "map", mapFile); VfsPath mapfilename = VfsPath(mapFile).ChangeExtension(L".pmp"); mapReader->LoadMap(mapfilename, CScriptValRooted(), &secondaryTerrain, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &secondaryContext, INVALID_PLAYER, true); // throws exception on failure } LDR_EndRegistering(); ENSURE(LDR_NonprogressiveLoad() == INFO::OK); ENSURE(secondaryComponentManager.DeserializeState(primaryStateBefore.state)); SerializationTestState secondaryStateBefore; ENSURE(secondaryComponentManager.SerializeState(secondaryStateBefore.state)); if (serializationTestDebugDump) ENSURE(secondaryComponentManager.DumpDebugState(secondaryStateBefore.debug, false)); if (serializationTestHash) ENSURE(secondaryComponentManager.ComputeStateHash(secondaryStateBefore.hash, false)); if (primaryStateBefore.state.str() != secondaryStateBefore.state.str() || primaryStateBefore.hash != secondaryStateBefore.hash) { ReportSerializationFailure(&primaryStateBefore, NULL, &secondaryStateBefore, NULL); } SerializationTestState primaryStateAfter; ENSURE(m_ComponentManager.SerializeState(primaryStateAfter.state)); if (serializationTestHash) ENSURE(m_ComponentManager.ComputeStateHash(primaryStateAfter.hash, false)); UpdateComponents(secondaryContext, turnLengthFixed, CloneCommandsFromOtherContext(m_ComponentManager.GetScriptInterface(), secondaryComponentManager.GetScriptInterface(), commands)); SerializationTestState secondaryStateAfter; ENSURE(secondaryComponentManager.SerializeState(secondaryStateAfter.state)); if (serializationTestHash) ENSURE(secondaryComponentManager.ComputeStateHash(secondaryStateAfter.hash, false)); if (primaryStateAfter.state.str() != secondaryStateAfter.state.str() || primaryStateAfter.hash != secondaryStateAfter.hash) { // Only do the (slow) dumping now we know we're going to need to report it ENSURE(m_ComponentManager.DumpDebugState(primaryStateAfter.debug, false)); ENSURE(secondaryComponentManager.DumpDebugState(secondaryStateAfter.debug, false)); ReportSerializationFailure(&primaryStateBefore, &primaryStateAfter, &secondaryStateBefore, &secondaryStateAfter); } } // if (m_TurnNumber == 0) // m_ComponentManager.GetScriptInterface().DumpHeap(); // Run the GC occasionally // (TODO: we ought to schedule this for a frame where we're not // running the sim update, to spread the load) if (m_TurnNumber % 1 == 0) m_ComponentManager.GetScriptInterface().MaybeIncrementalRuntimeGC(); if (m_EnableOOSLog) DumpState(); // Start computing AI for the next turn CmpPtr<ICmpAIManager> cmpAIManager(m_SimContext, SYSTEM_ENTITY); if (cmpAIManager) cmpAIManager->StartComputation(); ++m_TurnNumber; }