mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-12 02:28:11 +02:00
Redesign loading solution
This commit is contained in:
parent
d9a2a7bfd0
commit
dfaf778d16
@ -182,8 +182,8 @@ void CClient::newGame(CGameState * initializedGameState)
|
||||
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
|
||||
if(!initializedGameState)
|
||||
{
|
||||
Load::Progress * progressTrackingPointer = nullptr;
|
||||
gs->init(&mapService, CSH->si.get(), progressTrackingPointer, settings["general"]["saveRandomMaps"].Bool());
|
||||
Load::ProgressAccumulator progressTracking;
|
||||
gs->init(&mapService, CSH->si.get(), progressTracking, settings["general"]["saveRandomMaps"].Bool());
|
||||
}
|
||||
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
|
||||
|
||||
|
@ -133,6 +133,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack
|
||||
if(auto w = GH.windows().topWindow<CLoadingScreen>())
|
||||
{
|
||||
w->finish();
|
||||
w->tick(0);
|
||||
w->redraw();
|
||||
}
|
||||
else
|
||||
@ -144,6 +145,7 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyLoadProgress(LobbyLoadProgress
|
||||
if(auto w = GH.windows().topWindow<CLoadingScreen>())
|
||||
{
|
||||
w->set(pack.progress);
|
||||
w->tick(0);
|
||||
w->redraw();
|
||||
}
|
||||
else
|
||||
|
@ -18,6 +18,11 @@ Progress::Progress(): _progress(std::numeric_limits<Type>::min())
|
||||
setupSteps(100);
|
||||
}
|
||||
|
||||
Progress::Progress(int steps): _progress(std::numeric_limits<Type>::min())
|
||||
{
|
||||
setupSteps(steps);
|
||||
}
|
||||
|
||||
Type Progress::get() const
|
||||
{
|
||||
if(_step >= _maxSteps)
|
||||
@ -82,3 +87,49 @@ void Progress::step(int 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);
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ namespace Load
|
||||
|
||||
using Type = unsigned char;
|
||||
|
||||
class ProgressAccumulator;
|
||||
|
||||
/*
|
||||
* Purpose of that class is to track progress of computations
|
||||
* Derive from this class if you want to translate user or system
|
||||
@ -29,8 +31,9 @@ class DLL_LINKAGE Progress
|
||||
public:
|
||||
|
||||
//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(int steps);
|
||||
virtual ~Progress() = default;
|
||||
|
||||
//Returns current state of the progress
|
||||
@ -67,5 +70,25 @@ public:
|
||||
private:
|
||||
std::atomic<Type> _progress, _target;
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -404,7 +404,7 @@ void CGameState::preInit(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();
|
||||
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())
|
||||
{
|
||||
@ -544,10 +544,10 @@ void CGameState::initNewGame(const IMapService * mapService, bool allowSavingRan
|
||||
|
||||
// Gen map
|
||||
CMapGenerator mapGenerator(*scenarioOps->mapGenOptions, scenarioOps->seedToBeUsed);
|
||||
progressTracking = &mapGenerator;
|
||||
progressTracking.include(mapGenerator);
|
||||
|
||||
std::unique_ptr<CMap> randomMap = mapGenerator.generate();
|
||||
progressTracking = nullptr;
|
||||
progressTracking.exclude(mapGenerator);
|
||||
|
||||
if(allowSavingRandomMap)
|
||||
{
|
||||
|
@ -90,7 +90,7 @@ public:
|
||||
|
||||
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);
|
||||
|
||||
ConstTransitivePtr<StartInfo> scenarioOps, initialOpts; //second one is a copy of settings received from pregame (not randomized)
|
||||
@ -167,7 +167,7 @@ public:
|
||||
private:
|
||||
// ----- initialization -----
|
||||
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 initGlobalBonuses();
|
||||
void initGrailPosition();
|
||||
|
@ -573,7 +573,7 @@ void CGameHandler::reinitScripting()
|
||||
#endif
|
||||
}
|
||||
|
||||
void CGameHandler::init(StartInfo *si, Load::Progress *& progressTracking)
|
||||
void CGameHandler::init(StartInfo *si, Load::ProgressAccumulator & progressTracking)
|
||||
{
|
||||
if (si->seedToBeUsed == 0)
|
||||
{
|
||||
|
@ -199,7 +199,7 @@ public:
|
||||
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 handleReceivedPack(CPackForServer * pack);
|
||||
PlayerColor getPlayerAt(std::shared_ptr<CConnection> c) const;
|
||||
|
@ -279,23 +279,20 @@ void CVCMIServer::prepareToRestart()
|
||||
|
||||
bool CVCMIServer::prepareToStartGame()
|
||||
{
|
||||
Load::Progress * progressTracking = nullptr;
|
||||
bool progressTrackingFinished = false;
|
||||
std::thread progressTrackingThread([this, &progressTracking, &progressTrackingFinished](){
|
||||
while(!progressTrackingFinished)
|
||||
Load::ProgressAccumulator progressTracking;
|
||||
Load::Progress current(1);
|
||||
progressTracking.include(current);
|
||||
|
||||
auto progressTrackingThread = boost::thread([this, &progressTracking]()
|
||||
{
|
||||
while(!progressTracking.finished())
|
||||
{
|
||||
if(progressTracking)
|
||||
{
|
||||
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
||||
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
|
||||
loadProgress->progress = progressTracking->get();
|
||||
addToAnnounceQueue(std::move(loadProgress));
|
||||
}
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
|
||||
std::unique_ptr<LobbyLoadProgress> loadProgress(new LobbyLoadProgress);
|
||||
loadProgress->progress = progressTracking.get();
|
||||
addToAnnounceQueue(std::move(loadProgress));
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
|
||||
}
|
||||
progressTrackingFinished = false;
|
||||
});
|
||||
progressTrackingThread.detach();
|
||||
|
||||
gh = std::make_shared<CGameHandler>(this);
|
||||
switch(si->mode)
|
||||
@ -315,7 +312,11 @@ bool CVCMIServer::prepareToStartGame()
|
||||
case StartInfo::LOAD_GAME:
|
||||
logNetwork->info("Preparing to start loaded game");
|
||||
if(!gh->load(si->mapname))
|
||||
{
|
||||
current.finish();
|
||||
progressTrackingThread.join();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
logNetwork->error("Wrong mode in StartInfo!");
|
||||
@ -323,11 +324,9 @@ bool CVCMIServer::prepareToStartGame()
|
||||
break;
|
||||
}
|
||||
|
||||
progressTrackingFinished = true;
|
||||
while(progressTrackingFinished)
|
||||
continue;
|
||||
current.finish();
|
||||
progressTrackingThread.join();
|
||||
|
||||
state = EServerState::GAMEPLAY_STARTING;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -289,9 +289,6 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
||||
result = false;
|
||||
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
|
||||
if(!srv.prepareToStartGame())
|
||||
@ -303,6 +300,7 @@ void ApplyOnServerNetPackVisitor::visitLobbyStartGame(LobbyStartGame & pack)
|
||||
pack.initializedStartInfo = std::make_shared<StartInfo>(*srv.gh->getStartInfo(true));
|
||||
pack.initializedGameState = srv.gh->gameState();
|
||||
|
||||
srv.state = EServerState::GAMEPLAY_STARTING;
|
||||
result = true;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user