Index: ps/trunk/source/graphics/GameView.h =================================================================== --- ps/trunk/source/graphics/GameView.h +++ ps/trunk/source/graphics/GameView.h @@ -43,7 +43,6 @@ void SetViewport(const SViewPort& vp); void RegisterInit(); - int Initialize(); /** * Updates all the view information (i.e. rotate camera, scroll, whatever). This will *not* change any Index: ps/trunk/source/graphics/GameView.cpp =================================================================== --- ps/trunk/source/graphics/GameView.cpp +++ ps/trunk/source/graphics/GameView.cpp @@ -49,7 +49,6 @@ #include "ps/Globals.h" #include "ps/Hotkey.h" #include "ps/Loader.h" -#include "ps/LoaderThunks.h" #include "ps/Profile.h" #include "ps/Pyrogenesis.h" #include "ps/TouchInput.h" @@ -207,18 +206,19 @@ return m->MiniMapTexture; } -int CGameView::Initialize() -{ - m->CameraController->LoadConfig(); - return 0; -} - void CGameView::RegisterInit() { // CGameView init - RegMemFun(this, &CGameView::Initialize, L"CGameView init", 1); + LDR_Register([this](const double) + { + m->CameraController->LoadConfig(); + return 0; + }, L"CGameView init", 1); - RegMemFun(g_TexMan.GetSingletonPtr(), &CTerrainTextureManager::LoadTerrainTextures, L"LoadTerrainTextures", 60); + LDR_Register([](const double) + { + return g_TexMan.LoadTerrainTextures(); + }, L"LoadTerrainTextures", 60); } void CGameView::BeginFrame() Index: ps/trunk/source/graphics/MapReader.h =================================================================== --- ps/trunk/source/graphics/MapReader.h +++ ps/trunk/source/graphics/MapReader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -73,9 +73,6 @@ // UnpackCinema: unpack the cinematic tracks from the input stream int UnpackCinema(); - // UnpackMap: unpack the given data from the raw data stream into local variables - int UnpackMap(); - // ApplyData: take all the input data, and rebuild the scene from it int ApplyData(); int ApplyTerrainData(); @@ -90,7 +87,7 @@ int LoadRMSettings(); // Generate random map - int GenerateMap(); + int GenerateMap(const CStrW& scriptFile); // Parse script data into terrain int ParseTerrain(); @@ -119,7 +116,6 @@ CStrW m_Script; // random map data - CStrW m_ScriptFile; JS::PersistentRootedValue m_ScriptSettings; JS::PersistentRootedValue m_MapData; Index: ps/trunk/source/graphics/MapReader.cpp =================================================================== --- ps/trunk/source/graphics/MapReader.cpp +++ ps/trunk/source/graphics/MapReader.cpp @@ -32,7 +32,6 @@ #include "maths/MathUtil.h" #include "ps/CLogger.h" #include "ps/Loader.h" -#include "ps/LoaderThunks.h" #include "ps/World.h" #include "ps/XML/Xeromyces.h" #include "renderer/PostprocManager.h" @@ -123,31 +122,58 @@ // load map or script settings script if (settings.isUndefined()) - RegMemFun(this, &CMapReader::LoadScriptSettings, L"CMapReader::LoadScriptSettings", 50); + LDR_Register([this](const double) + { + return LoadScriptSettings(); + }, L"CMapReader::LoadScriptSettings", 50); else - RegMemFun(this, &CMapReader::LoadRMSettings, L"CMapReader::LoadRMSettings", 50); + LDR_Register([this](const double) + { + return LoadRMSettings(); + }, L"CMapReader::LoadRMSettings", 50); // load player settings script (must be done before reading map) - RegMemFun(this, &CMapReader::LoadPlayerSettings, L"CMapReader::LoadPlayerSettings", 50); + LDR_Register([this](const double) + { + return LoadPlayerSettings(); + }, L"CMapReader::LoadPlayerSettings", 50); // unpack the data if (!only_xml) - RegMemFun(this, &CMapReader::UnpackMap, L"CMapReader::UnpackMap", 1200); + LDR_Register([this](const double) + { + return UnpackTerrain(); + }, L"CMapReader::UnpackMap", 1200); // read the corresponding XML file - RegMemFun(this, &CMapReader::ReadXML, L"CMapReader::ReadXML", 50); + LDR_Register([this](const double) + { + return ReadXML(); + }, L"CMapReader::ReadXML", 50); // apply terrain data to the world - RegMemFun(this, &CMapReader::ApplyTerrainData, L"CMapReader::ApplyTerrainData", 5); + LDR_Register([this](const double) + { + return ApplyTerrainData(); + }, L"CMapReader::ApplyTerrainData", 5); // read entities - RegMemFun(this, &CMapReader::ReadXMLEntities, L"CMapReader::ReadXMLEntities", 5800); + LDR_Register([this](const double) + { + return ReadXMLEntities(); + }, L"CMapReader::ReadXMLEntities", 5800); // apply misc data to the world - RegMemFun(this, &CMapReader::ApplyData, L"CMapReader::ApplyData", 5); + LDR_Register([this](const double) + { + return ApplyData(); + }, L"CMapReader::ApplyData", 5); // load map settings script (must be done after reading map) - RegMemFun(this, &CMapReader::LoadMapSettings, L"CMapReader::LoadMapSettings", 5); + LDR_Register([this](const double) + { + return LoadMapSettings(); + }, L"CMapReader::LoadMapSettings", 5); } // LoadRandomMap: try to load the map data; reinitialise the scene to new data if successful @@ -156,7 +182,6 @@ CLightEnv *pLightEnv_, CGameView *pGameView_, CCinemaManager* pCinema_, CTriggerManager* pTrigMan_, CPostprocManager* pPostproc_, CSimulation2 *pSimulation2_, int playerID_) { - m_ScriptFile = scriptFile; pSimulation2 = pSimulation2_; pSimContext = pSimulation2 ? &pSimulation2->GetSimContext() : NULL; m_ScriptSettings.init(cx.GetGeneralJSContext(), settings); @@ -179,40 +204,64 @@ only_xml = false; // copy random map settings (before entity creation) - RegMemFun(this, &CMapReader::LoadRMSettings, L"CMapReader::LoadRMSettings", 50); + LDR_Register([this](const double) + { + return LoadRMSettings(); + }, L"CMapReader::LoadRMSettings", 50); // load player settings script (must be done before reading map) - RegMemFun(this, &CMapReader::LoadPlayerSettings, L"CMapReader::LoadPlayerSettings", 50); + LDR_Register([this](const double) + { + return LoadPlayerSettings(); + }, L"CMapReader::LoadPlayerSettings", 50); // load map generator with random map script - RegMemFun(this, &CMapReader::GenerateMap, L"CMapReader::GenerateMap", 20000); + LDR_Register([this, scriptFile](const double) + { + return GenerateMap(scriptFile); + }, L"CMapReader::GenerateMap", 20000); // parse RMS results into terrain structure - RegMemFun(this, &CMapReader::ParseTerrain, L"CMapReader::ParseTerrain", 500); + LDR_Register([this](const double) + { + return ParseTerrain(); + }, L"CMapReader::ParseTerrain", 500); // parse RMS results into environment settings - RegMemFun(this, &CMapReader::ParseEnvironment, L"CMapReader::ParseEnvironment", 5); + LDR_Register([this](const double) + { + return ParseEnvironment(); + }, L"CMapReader::ParseEnvironment", 5); // parse RMS results into camera settings - RegMemFun(this, &CMapReader::ParseCamera, L"CMapReader::ParseCamera", 5); + LDR_Register([this](const double) + { + return ParseCamera(); + }, L"CMapReader::ParseCamera", 5); // apply terrain data to the world - RegMemFun(this, &CMapReader::ApplyTerrainData, L"CMapReader::ApplyTerrainData", 5); + LDR_Register([this](const double) + { + return ApplyTerrainData(); + }, L"CMapReader::ApplyTerrainData", 5); // parse RMS results into entities - RegMemFun(this, &CMapReader::ParseEntities, L"CMapReader::ParseEntities", 1000); + LDR_Register([this](const double) + { + return ParseEntities(); + }, L"CMapReader::ParseEntities", 1000); // apply misc data to the world - RegMemFun(this, &CMapReader::ApplyData, L"CMapReader::ApplyData", 5); + LDR_Register([this](const double) + { + return ApplyData(); + }, L"CMapReader::ApplyData", 5); // load map settings script (must be done after reading map) - RegMemFun(this, &CMapReader::LoadMapSettings, L"CMapReader::LoadMapSettings", 5); -} - -// UnpackMap: unpack the given data from the raw data stream into local variables -int CMapReader::UnpackMap() -{ - return UnpackTerrain(); + LDR_Register([this](const double) + { + return LoadMapSettings(); + }, L"CMapReader::LoadMapSettings", 5); } // UnpackTerrain: unpack the terrain from the end of the input data stream @@ -1271,7 +1320,7 @@ return 0; } -int CMapReader::GenerateMap() +int CMapReader::GenerateMap(const CStrW& scriptFile) { ScriptRequest rq(pSimulation2->GetScriptInterface()); @@ -1282,8 +1331,8 @@ VfsPath scriptPath; - if (m_ScriptFile.length()) - scriptPath = L"maps/random/"+m_ScriptFile; + if (scriptFile.length()) + scriptPath = L"maps/random/" + scriptFile; // Stringify settings to pass across threads std::string scriptSettings = Script::StringifyJSON(rq, &m_ScriptSettings); Index: ps/trunk/source/ps/Game.h =================================================================== --- ps/trunk/source/ps/Game.h +++ ps/trunk/source/ps/Game.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -211,8 +211,7 @@ std::vector m_PlayerColors; - int LoadInitialState(); - std::string m_InitialSavedState; // valid between RegisterInit and LoadInitialState + int LoadInitialState(const std::string& savedState); bool m_IsSavedGame; // true if loading a saved game; false for a new game int LoadVisualReplayData(); Index: ps/trunk/source/ps/Game.cpp =================================================================== --- ps/trunk/source/ps/Game.cpp +++ ps/trunk/source/ps/Game.cpp @@ -34,7 +34,6 @@ #include "ps/CStr.h" #include "ps/GameSetup/GameSetup.h" #include "ps/Loader.h" -#include "ps/LoaderThunks.h" #include "ps/Profile.h" #include "ps/Replay.h" #include "ps/World.h" @@ -215,7 +214,6 @@ const ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface(); ScriptRequest rq(scriptInterface); - m_InitialSavedState = savedState; m_IsSavedGame = !savedState.empty(); m_Simulation2->SetInitAttributes(attribs); @@ -234,7 +232,10 @@ LDR_BeginRegistering(); - RegMemFun(m_Simulation2, &CSimulation2::ProgressiveLoad, L"Simulation init", 1000); + LDR_Register([this](const double) + { + return m_Simulation2->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 @@ -265,26 +266,31 @@ m_World->RegisterInit(mapFile, *scriptInterface.GetContext(), settings, m_PlayerID); } if (m_GameView) - RegMemFun(&g_Renderer.GetSceneRenderer().GetWaterManager(), &WaterManager::LoadWaterTextures, L"LoadWaterTextures", 80); + LDR_Register([&waterManager = g_Renderer.GetSceneRenderer().GetWaterManager()](const double) + { + return waterManager.LoadWaterTextures(); + }, L"LoadWaterTextures", 80); if (m_IsSavedGame) - RegMemFun(this, &CGame::LoadInitialState, L"Loading game", 1000); + LDR_Register([this, savedState](const double) + { + return LoadInitialState(savedState); + }, L"Loading game", 1000); if (m_IsVisualReplay) - RegMemFun(this, &CGame::LoadVisualReplayData, L"Loading visual replay data", 1000); + LDR_Register([this](const double) + { + return LoadVisualReplayData(); + }, L"Loading visual replay data", 1000); LDR_EndRegistering(); } -int CGame::LoadInitialState() +int CGame::LoadInitialState(const std::string& savedState) { ENSURE(m_IsSavedGame); - ENSURE(!m_InitialSavedState.empty()); - - std::string state; - m_InitialSavedState.swap(state); // deletes the original to save a bit of memory - std::stringstream stream(state); + std::stringstream stream(savedState); bool ok = m_Simulation2->DeserializeState(stream); if (!ok) Index: ps/trunk/source/ps/Loader.h =================================================================== --- ps/trunk/source/ps/Loader.h +++ ps/trunk/source/ps/Loader.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -21,6 +21,7 @@ #ifndef INCLUDED_LOADER #define INCLUDED_LOADER +#include #include /* @@ -84,13 +85,10 @@ Replace the InitEverything() function with the following: LDR_BeginRegistering(); - LDR_Register(..) for each sub-function (*) + LDR_Register(..) for each sub-function LDR_EndRegistering(); Then in the main loop, call LDR_ProgressiveLoad(). -* RegMemFun from LoaderThunks.h may be used instead; it takes care of -registering member functions, which would otherwise be messy. - */ @@ -105,7 +103,7 @@ // callback function of a task; performs the actual work. -// it receives a param (see below) and the exact time remaining [s]. +// it receives the time remaining [s]. // // return semantics: // - if the entire task was successfully completed, return 0; @@ -116,18 +114,16 @@ // != 0, or it's treated as "finished") // - on failure, return a negative error code or 'warning' (see above); // LDR_ProgressiveLoad will abort immediately and return that. -typedef int (*LoadFunc)(std::shared_ptr param, double time_left); +using LoadFunc = std::function; // register a task (later processed in FIFO order). // : function that will perform the actual work; see LoadFunc. -// : (optional) parameter/persistent state. // : user-visible description of the current task, e.g. // "Loading Textures". // : used to calculate progress, and when checking // whether there is enough of the time budget left to process this task // (reduces timeslice overruns, making the main loop more responsive). -extern void LDR_Register(LoadFunc func, std::shared_ptr param, const wchar_t* description, - int estimated_duration_ms); +void LDR_Register(LoadFunc func, const wchar_t* description, int estimated_duration_ms); // call when finished registering tasks; subsequent calls to Index: ps/trunk/source/ps/Loader.cpp =================================================================== --- ps/trunk/source/ps/Loader.cpp +++ ps/trunk/source/ps/Loader.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2019 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -26,7 +26,6 @@ #include "lib/timer.h" #include "CStr.h" #include "Loader.h" -#include "LoaderThunks.h" // set by LDR_EndRegistering; may be 0 during development when @@ -63,18 +62,14 @@ LoadFunc func; - // MemFun_t instance - std::shared_ptr param; - // Translatable string shown to the player. CStrW description; int estimated_duration_ms; // LDR_Register gets these as parameters; pack everything together. - LoadRequest(LoadFunc func_, std::shared_ptr param_, const wchar_t* desc_, int ms_) - : func(func_), param(param_), description(desc_), - estimated_duration_ms(ms_) + LoadRequest(LoadFunc func_, const wchar_t* desc_, int ms_) + : func(func_), description(desc_), estimated_duration_ms(ms_) { } }; @@ -82,6 +77,13 @@ typedef std::deque LoadRequests; static LoadRequests load_requests; +// Returns true if the return code indicates that the `LoadRequest` didn't +// finish and should be reinvoked in the next frame. +static bool ldr_was_interrupted(const int ret) +{ + return 0 < ret && ret <= 100; +} + // call before starting to register load requests. // this routine is provided so we can prevent 2 simultaneous load operations, // which is bogus. that can happen by clicking the load button quickly, @@ -103,13 +105,11 @@ // : used to calculate progress, and when checking // whether there is enough of the time budget left to process this task // (reduces timeslice overruns, making the main loop more responsive). -void LDR_Register(LoadFunc func, std::shared_ptr param, const wchar_t* description, - int estimated_duration_ms) +void LDR_Register(LoadFunc func, const wchar_t* description, int estimatedDurationMs) { ENSURE(state == REGISTERING); // must be called between LDR_(Begin|End)Register - const LoadRequest lr(func, param, description, estimated_duration_ms); - load_requests.push_back(lr); + load_requests.emplace_back(std::move(func), description, estimatedDurationMs); } @@ -214,7 +214,7 @@ // call this task's function and bill elapsed time. const double t0 = timer_Time(); - int status = lr.func(lr.param, time_left); + const int status = lr.func(time_left); const bool timed_out = ldr_was_interrupted(status); const double elapsed_time = timer_Time() - t0; time_left -= elapsed_time; Index: ps/trunk/source/ps/LoaderThunks.h =================================================================== --- ps/trunk/source/ps/LoaderThunks.h +++ ps/trunk/source/ps/LoaderThunks.h @@ -1,77 +0,0 @@ -/* Copyright (C) 2021 Wildfire Games. - * This file is part of 0 A.D. - * - * 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 - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * 0 A.D. is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with 0 A.D. If not, see . - */ - -#ifndef INCLUDED_LOADERTHUNKS -#define INCLUDED_LOADERTHUNKS - -// does this return code indicate the coroutine yielded and -// wasn't yet finished? -static inline bool ldr_was_interrupted(int ret) -{ - return (0 < ret && ret <= 100); -} - -template struct MemFun_t -{ - NONCOPYABLE(MemFun_t); -public: - T* const this_; - int (T::*func)(void); - MemFun_t(T* this__, int(T::*func_)(void)) - : this_(this__), func(func_) {} -}; - -template static int MemFunThunk(std::shared_ptr param, double UNUSED(time_left)) -{ - MemFun_t* const mf = static_cast*>(param.get()); - return (mf->this_->*mf->func)(); -} - -template void RegMemFun(T* this_, int(T::*func)(void), - const wchar_t* description, int estimated_duration_ms) -{ - LDR_Register(MemFunThunk, std::make_shared>(this_, func), description, estimated_duration_ms); -} - - -//////////////////////////////////////////////////////// - - -template struct MemFun1_t -{ - NONCOPYABLE(MemFun1_t); -public: - T* const this_; - Arg arg; - int (T::*func)(Arg); - MemFun1_t(T* this__, int(T::*func_)(Arg), Arg arg_) - : this_(this__), func(func_), arg(arg_) {} -}; - -template static int MemFun1Thunk(std::shared_ptr param, double UNUSED(time_left)) -{ - MemFun1_t* const mf = static_cast*>(param.get()); - return (mf->this_->*mf->func)(mf->arg); -} - -template void RegMemFun1(T* this_, int(T::*func)(Arg), Arg arg, - const wchar_t* description, int estimated_duration_ms) -{ - LDR_Register(MemFun1Thunk, std::make_shared >(this_, func, arg), description, estimated_duration_ms); -} - -#endif // INCLUDED_LOADERTHUNKS Index: ps/trunk/source/ps/World.cpp =================================================================== --- ps/trunk/source/ps/World.cpp +++ ps/trunk/source/ps/World.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2022 Wildfire Games. +/* Copyright (C) 2023 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -30,7 +30,6 @@ #include "ps/Errors.h" #include "ps/Game.h" #include "ps/Loader.h" -#include "ps/LoaderThunks.h" #include "ps/World.h" #include "renderer/Renderer.h" #include "renderer/SceneRenderer.h" @@ -78,7 +77,10 @@ pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL, m_pGame->GetSimulation2(), &m_pGame->GetSimulation2()->GetSimContext(), playerID, false); // fails immediately, or registers for delay loading - RegMemFun(this, &CWorld::DeleteMapReader, L"CWorld::DeleteMapReader", 5); + LDR_Register([this](const double) + { + return DeleteMapReader(); + }, L"CWorld::DeleteMapReader", 5); } catch (PSERROR_File& err) { @@ -101,7 +103,10 @@ pTriggerManager, CRenderer::IsInitialised() ? &g_Renderer.GetPostprocManager() : NULL, m_pGame->GetSimulation2(), playerID); // registers for delay loading - RegMemFun(this, &CWorld::DeleteMapReader, L"CWorld::DeleteMapReader", 5); + LDR_Register([this](const double) + { + return DeleteMapReader(); + }, L"CWorld::DeleteMapReader", 5); } int CWorld::DeleteMapReader()