1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-23 00:28:08 +02:00

Redesign loading solution

This commit is contained in:
nordsoft
2023-08-22 20:10:20 +04:00
parent d9a2a7bfd0
commit dfaf778d16
10 changed files with 105 additions and 32 deletions

View File

@ -182,8 +182,8 @@ void CClient::newGame(CGameState * initializedGameState)
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff()); logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
if(!initializedGameState) if(!initializedGameState)
{ {
Load::Progress * progressTrackingPointer = nullptr; Load::ProgressAccumulator progressTracking;
gs->init(&mapService, CSH->si.get(), progressTrackingPointer, settings["general"]["saveRandomMaps"].Bool()); gs->init(&mapService, CSH->si.get(), progressTracking, settings["general"]["saveRandomMaps"].Bool());
} }
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff()); logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());

View File

@ -133,6 +133,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack
if(auto w = GH.windows().topWindow<CLoadingScreen>()) if(auto w = GH.windows().topWindow<CLoadingScreen>())
{ {
w->finish(); w->finish();
w->tick(0);
w->redraw(); w->redraw();
} }
else else
@ -144,6 +145,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyLoadProgress(LobbyLoadProgress
if(auto w = GH.windows().topWindow<CLoadingScreen>()) if(auto w = GH.windows().topWindow<CLoadingScreen>())
{ {
w->set(pack.progress); w->set(pack.progress);
w->tick(0);
w->redraw(); w->redraw();
} }
else else

View File

@ -18,6 +18,11 @@ Progress::Progress(): _progress(std::numeric_limits<Type>::min())
setupSteps(100); setupSteps(100);
} }
Progress::Progress(int steps): _progress(std::numeric_limits<Type>::min())
{
setupSteps(steps);
}
Type Progress::get() const Type Progress::get() const
{ {
if(_step >= _maxSteps) if(_step >= _maxSteps)
@ -82,3 +87,49 @@ void Progress::step(int count)
_step += count; _step += count;
} }
} }
void ProgressAccumulator::include(const Progress & p)
{
boost::unique_lock<boost::mutex> guard(_mx);
_progress.emplace_back(p);
}
void ProgressAccumulator::exclude(const Progress & p)
{
boost::unique_lock<boost::mutex> guard(_mx);
for(auto i = _progress.begin(); i != _progress.end(); ++i)
{
if(&i->get() == &p)
{
_accumulated += static_cast<long long>(p.get()) * p._maxSteps;
_steps += p._maxSteps;
_progress.erase(i);
return;
}
}
}
bool ProgressAccumulator::finished() const
{
boost::unique_lock<boost::mutex> guard(_mx);
for(auto i : _progress)
if(!i.get().finished())
return false;
return true;
}
Type ProgressAccumulator::get() const
{
boost::unique_lock<boost::mutex> guard(_mx);
auto sum = _accumulated;
auto totalSteps = _steps;
for(auto p : _progress)
{
sum += static_cast<long long>(p.get().get()) * p.get()._maxSteps;
totalSteps += p.get()._maxSteps;
}
if(totalSteps)
sum /= totalSteps;
return static_cast<Type>(sum);
}

View File

@ -18,6 +18,8 @@ namespace Load
using Type = unsigned char; using Type = unsigned char;
class ProgressAccumulator;
/* /*
* Purpose of that class is to track progress of computations * Purpose of that class is to track progress of computations
* Derive from this class if you want to translate user or system * Derive from this class if you want to translate user or system
@ -29,8 +31,9 @@ class DLL_LINKAGE Progress
public: public:
//Sets current state to 0. //Sets current state to 0.
//Amount of steps to finish progress will be equal to 100 //Amount of steps to finish progress will be equal to 100 for default constructor
Progress(); Progress();
Progress(int steps);
virtual ~Progress() = default; virtual ~Progress() = default;
//Returns current state of the progress //Returns current state of the progress
@ -67,5 +70,25 @@ public:
private: private:
std::atomic<Type> _progress, _target; std::atomic<Type> _progress, _target;
std::atomic<int> _step, _maxSteps; std::atomic<int> _step, _maxSteps;
friend class ProgressAccumulator;
}; };
class DLL_LINKAGE ProgressAccumulator
{
public:
ProgressAccumulator() = default;
void include(const Progress &);
void exclude(const Progress &);
bool finished() const;
Type get() const;
private:
mutable boost::mutex _mx;
long long _accumulated = 0, _steps = 0;
std::vector<std::reference_wrapper<const Progress>> _progress;
};
} }

View File

@ -404,7 +404,7 @@ void CGameState::preInit(Services * services)
this->services = services; this->services = services;
} }
void CGameState::init(const IMapService * mapService, StartInfo * si, Load::Progress *& progressTracking, bool allowSavingRandomMap) void CGameState::init(const IMapService * mapService, StartInfo * si, Load::ProgressAccumulator & progressTracking, bool allowSavingRandomMap)
{ {
preInitAuto(); preInitAuto();
logGlobal->info("\tUsing random seed: %d", si->seedToBeUsed); logGlobal->info("\tUsing random seed: %d", si->seedToBeUsed);
@ -535,7 +535,7 @@ void CGameState::preInitAuto()
} }
} }
void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::Progress *& progressTracking) void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::ProgressAccumulator & progressTracking)
{ {
if(scenarioOps->createRandomMap()) if(scenarioOps->createRandomMap())
{ {
@ -544,10 +544,10 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
// Gen map // Gen map
CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed); CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
progressTracking = &mapGenerator; progressTracking.include(mapGenerator);
std::unique_ptr<CMap> randomMap = mapGenerator.generate(); std::unique_ptr<CMap> randomMap = mapGenerator.generate();
progressTracking = nullptr; progressTracking.exclude(mapGenerator);
if(allowSavingRandomMap) if(allowSavingRandomMap)
{ {

View File

@ -90,7 +90,7 @@ public:
void preInit(Services * services); void preInit(Services * services);
void init(const IMapService * mapService, StartInfo * si, Load::Progress *&, bool allowSavingRandomMap = false); void init(const IMapService * mapService, StartInfo * si, Load::ProgressAccumulator &, bool allowSavingRandomMap = false);
void updateOnLoad(StartInfo * si); void updateOnLoad(StartInfo * si);
ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized) ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
@ -167,7 +167,7 @@ public:
private: private:
// ----- initialization ----- // ----- initialization -----
void preInitAuto(); void preInitAuto();
void initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::Progress *& progressTracking); void initNewGame(const IMapService * mapService, bool allowSavingRandomMap, Load::ProgressAccumulator & progressTracking);
void checkMapChecksum(); void checkMapChecksum();
void initGlobalBonuses(); void initGlobalBonuses();
void initGrailPosition(); void initGrailPosition();

View File

@ -573,7 +573,7 @@ void CGameHandler::reinitScripting()
#endif #endif
} }
void CGameHandler::init(StartInfo *si, Load::Progress *& progressTracking) void CGameHandler::init(StartInfo *si, Load::ProgressAccumulator & progressTracking)
{ {
if (si->seedToBeUsed == 0) if (si->seedToBeUsed == 0)
{ {

View File

@ -199,7 +199,7 @@ public:
void expGiven(const CGHeroInstance *hero); //triggers needed level-ups, handles also commander of this hero void expGiven(const CGHeroInstance *hero); //triggers needed level-ups, handles also commander of this hero
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
void init(StartInfo *si, Load::Progress *& progressTracking); void init(StartInfo *si, Load::ProgressAccumulator & progressTracking);
void handleClientDisconnection(std::shared_ptr<CConnection> c); void handleClientDisconnection(std::shared_ptr<CConnection> c);
void handleReceivedPack(CPackForServer * pack); void handleReceivedPack(CPackForServer * pack);
PlayerColor getPlayerAt(std::shared_ptr<CConnection> c) const; PlayerColor getPlayerAt(std::shared_ptr<CConnection> c) const;

View File

@ -279,23 +279,20 @@ void CVCMIServer::prepareToRestart()
bool CVCMIServer::prepareToStartGame() bool CVCMIServer::prepareToStartGame()
{ {
Load::Progress * progressTracking = nullptr; Load::ProgressAccumulator progressTracking;
bool progressTrackingFinished = false; Load::Progress current(1);
std::thread progressTrackingThread([this, &progressTracking, &progressTrackingFinished](){ progressTracking.include(current);
while(!progressTrackingFinished)
auto progressTrackingThread = boost::thread([this, &progressTracking]()
{
while(!progressTracking.finished())
{ {
if(progressTracking) std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
{ loadProgress->progress = progressTracking.get();
boost::unique_lock<boost::recursive_mutex> queueLock(mx); addToAnnounceQueue(std::move(loadProgress));
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress); boost::this_thread::sleep(boost::posix_time::milliseconds(50));
loadProgress->progress = progressTracking->get();
addToAnnounceQueue(std::move(loadProgress));
}
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
} }
progressTrackingFinished = false;
}); });
progressTrackingThread.detach();
gh = std::make_shared<CGameHandler>(this); gh = std::make_shared<CGameHandler>(this);
switch(si->mode) switch(si->mode)
@ -315,7 +312,11 @@ bool CVCMIServer::prepareToStartGame()
case StartInfo::LOAD_GAME: case StartInfo::LOAD_GAME:
logNetwork->info("Preparing to start loaded game"); logNetwork->info("Preparing to start loaded game");
if(!gh->load(si->mapname)) if(!gh->load(si->mapname))
{
current.finish();
progressTrackingThread.join();
return false; return false;
}
break; break;
default: default:
logNetwork->error("Wrong mode in StartInfo!"); logNetwork->error("Wrong mode in StartInfo!");
@ -323,11 +324,9 @@ bool CVCMIServer::prepareToStartGame()
break; break;
} }
progressTrackingFinished = true; current.finish();
while(progressTrackingFinished) progressTrackingThread.join();
continue;
state = EServerState::GAMEPLAY_STARTING;
return true; return true;
} }

View File

@ -289,9 +289,6 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
result = false; result = false;
return; return;
} }
// Announce loading
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
srv.addToAnnounceQueue(std::move(loadProgress));
// Server will prepare gamestate and we announce StartInfo to clients // Server will prepare gamestate and we announce StartInfo to clients
if(!srv.prepareToStartGame()) if(!srv.prepareToStartGame())
@ -303,6 +300,7 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true)); pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true));
pack.initializedGameState = srv.gh->gameState(); pack.initializedGameState = srv.gh->gameState();
srv.state = EServerState::GAMEPLAY_STARTING;
result = true; result = true;
} }