1
1
forked from 0ad/0ad

Use std::function in the Loader.

Accepted By: @wraitii
Differential Revision: https://code.wildfiregames.com/D4989
This was SVN commit r27740.
This commit is contained in:
phosit 2023-06-26 18:35:34 +00:00
parent f3adb5d075
commit 766b0820f7
10 changed files with 138 additions and 165 deletions

View File

@ -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 @@ CMiniMapTexture& CGameView::GetMiniMapTexture()
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()

View File

@ -43,7 +43,6 @@ public:
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

View File

@ -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 @@ void CMapReader::LoadMap(const VfsPath& pathname, const ScriptContext& cx, JS::
// 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 @@ void CMapReader::LoadRandomMap(const CStrW& scriptFile, const ScriptContext& cx,
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 @@ void CMapReader::LoadRandomMap(const CStrW& scriptFile, const ScriptContext& cx,
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 @@ int CMapReader::LoadRMSettings()
return 0;
}
int CMapReader::GenerateMap()
int CMapReader::GenerateMap(const CStrW& scriptFile)
{
ScriptRequest rq(pSimulation2->GetScriptInterface());
@ -1282,8 +1331,8 @@ int CMapReader::GenerateMap()
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);

View File

@ -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 @@ private:
// 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 @@ private:
int LoadRMSettings();
// Generate random map
int GenerateMap();
int GenerateMap(const CStrW& scriptFile);
// Parse script data into terrain
int ParseTerrain();
@ -119,7 +116,6 @@ private:
CStrW m_Script;
// random map data
CStrW m_ScriptFile;
JS::PersistentRootedValue m_ScriptSettings;
JS::PersistentRootedValue m_MapData;

View File

@ -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 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
const ScriptInterface& scriptInterface = m_Simulation2->GetScriptInterface();
ScriptRequest rq(scriptInterface);
m_InitialSavedState = savedState;
m_IsSavedGame = !savedState.empty();
m_Simulation2->SetInitAttributes(attribs);
@ -234,7 +232,10 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
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 @@ void CGame::RegisterInit(const JS::HandleValue attribs, const std::string& saved
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)

View File

@ -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 @@ private:
std::vector<CColor> 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();

View File

@ -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 @@ struct LoadRequest
LoadFunc func;
// MemFun_t<T> instance
std::shared_ptr<void> 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<void> 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 @@ struct LoadRequest
typedef std::deque<LoadRequest> 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 @@ void LDR_BeginRegistering()
// <estimated_duration_ms>: 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<void> 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 @@ Status LDR_ProgressiveLoad(double time_budget, wchar_t* description, size_t max_
// 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;

View File

@ -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 <functional>
#include <wchar.h>
/*
@ -84,13 +85,10 @@ Intended Use
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 @@ extern void LDR_BeginRegistering();
// 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 @@ extern void LDR_BeginRegistering();
// != 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<void> param, double time_left);
using LoadFunc = std::function<int(double)>;
// register a task (later processed in FIFO order).
// <func>: function that will perform the actual work; see LoadFunc.
// <param>: (optional) parameter/persistent state.
// <description>: user-visible description of the current task, e.g.
// "Loading Textures".
// <estimated_duration_ms>: 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<void> 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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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<class T> 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<class T> static int MemFunThunk(std::shared_ptr<void> param, double UNUSED(time_left))
{
MemFun_t<T>* const mf = static_cast<MemFun_t<T>*>(param.get());
return (mf->this_->*mf->func)();
}
template<class T> void RegMemFun(T* this_, int(T::*func)(void),
const wchar_t* description, int estimated_duration_ms)
{
LDR_Register(MemFunThunk<T>, std::make_shared<MemFun_t<T>>(this_, func), description, estimated_duration_ms);
}
////////////////////////////////////////////////////////
template<class T, class Arg> 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<class T, class Arg> static int MemFun1Thunk(std::shared_ptr<void> param, double UNUSED(time_left))
{
MemFun1_t<T, Arg>* const mf = static_cast<MemFun1_t<T, Arg>*>(param.get());
return (mf->this_->*mf->func)(mf->arg);
}
template<class T, class Arg> void RegMemFun1(T* this_, int(T::*func)(Arg), Arg arg,
const wchar_t* description, int estimated_duration_ms)
{
LDR_Register(MemFun1Thunk<T, Arg>, std::make_shared<MemFun1_t<T, Arg> >(this_, func, arg), description, estimated_duration_ms);
}
#endif // INCLUDED_LOADERTHUNKS

View File

@ -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 @@ void CWorld::RegisterInit(const CStrW& mapFile, const ScriptContext& cx, JS::Han
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 @@ void CWorld::RegisterInitRMS(const CStrW& scriptFile, const ScriptContext& cx, J
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()