mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-23 22:37:55 +02:00
@@ -1367,7 +1367,7 @@ static void handleEvent(SDL_Event & ev)
|
||||
break;
|
||||
case EUserEvent::RESTART_GAME:
|
||||
{
|
||||
CSH->sendStartGame();
|
||||
CSH->sendRestartGame();
|
||||
}
|
||||
break;
|
||||
case EUserEvent::CAMPAIGN_START_SCENARIO:
|
||||
|
||||
@@ -512,6 +512,14 @@ void CServerHandler::sendGuiAction(ui8 action) const
|
||||
sendLobbyPack(lga);
|
||||
}
|
||||
|
||||
void CServerHandler::sendRestartGame() const
|
||||
{
|
||||
LobbyEndGame endGame;
|
||||
endGame.closeConnection = false;
|
||||
endGame.restart = true;
|
||||
sendLobbyPack(endGame);
|
||||
}
|
||||
|
||||
void CServerHandler::sendStartGame(bool allowOnlyAI) const
|
||||
{
|
||||
verifyStateBeforeStart(allowOnlyAI ? true : settings["session"]["onlyai"].Bool());
|
||||
@@ -524,9 +532,11 @@ void CServerHandler::sendStartGame(bool allowOnlyAI) const
|
||||
* si = * lsg.initializedStartInfo;
|
||||
}
|
||||
sendLobbyPack(lsg);
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
|
||||
void CServerHandler::startGameplay()
|
||||
void CServerHandler::startGameplay(CGameState * gameState)
|
||||
{
|
||||
if(CMM)
|
||||
CMM->disable();
|
||||
@@ -535,13 +545,13 @@ void CServerHandler::startGameplay()
|
||||
switch(si->mode)
|
||||
{
|
||||
case StartInfo::NEW_GAME:
|
||||
client->newGame();
|
||||
client->newGame(gameState);
|
||||
break;
|
||||
case StartInfo::CAMPAIGN:
|
||||
client->newGame();
|
||||
client->newGame(gameState);
|
||||
break;
|
||||
case StartInfo::LOAD_GAME:
|
||||
client->loadGame();
|
||||
client->loadGame(gameState);
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid mode");
|
||||
@@ -576,6 +586,9 @@ void CServerHandler::endGameplay(bool closeConnection, bool restart)
|
||||
GH.curInt = CMainMenu::create().get();
|
||||
}
|
||||
}
|
||||
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
|
||||
void CServerHandler::startCampaignScenario(std::shared_ptr<CCampaignState> cs)
|
||||
|
||||
@@ -21,6 +21,7 @@ class PlayerColor;
|
||||
struct StartInfo;
|
||||
|
||||
class CMapInfo;
|
||||
class CGameState;
|
||||
struct ClientPlayer;
|
||||
struct CPack;
|
||||
struct CPackForLobby;
|
||||
@@ -69,6 +70,7 @@ public:
|
||||
virtual void sendMessage(const std::string & txt) const = 0;
|
||||
virtual void sendGuiAction(ui8 action) const = 0; // TODO: possibly get rid of it?
|
||||
virtual void sendStartGame(bool allowOnlyAI = false) const = 0;
|
||||
virtual void sendRestartGame() const = 0;
|
||||
};
|
||||
|
||||
/// structure to handle running server and connecting to it
|
||||
@@ -142,9 +144,10 @@ public:
|
||||
void setTurnLength(int npos) const override;
|
||||
void sendMessage(const std::string & txt) const override;
|
||||
void sendGuiAction(ui8 action) const override;
|
||||
void sendRestartGame() const override;
|
||||
void sendStartGame(bool allowOnlyAI = false) const override;
|
||||
|
||||
void startGameplay();
|
||||
void startGameplay(CGameState * gameState = nullptr);
|
||||
void endGameplay(bool closeConnection = true, bool restart = false);
|
||||
void startCampaignScenario(std::shared_ptr<CCampaignState> cs = {});
|
||||
void showServerError(std::string txt);
|
||||
|
||||
@@ -180,14 +180,15 @@ events::EventBus * CClient::eventBus() const
|
||||
return clientEventBus.get();
|
||||
}
|
||||
|
||||
void CClient::newGame()
|
||||
void CClient::newGame(CGameState * initializedGameState)
|
||||
{
|
||||
CSH->th->update();
|
||||
CMapService mapService;
|
||||
gs = new CGameState();
|
||||
gs = initializedGameState ? initializedGameState : new CGameState();
|
||||
gs->preInit(VLC);
|
||||
logNetwork->trace("\tCreating gamestate: %i", CSH->th->getDiff());
|
||||
gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool());
|
||||
if(!initializedGameState)
|
||||
gs->init(&mapService, CSH->si.get(), settings["general"]["saveRandomMaps"].Bool());
|
||||
logNetwork->trace("Initializing GameState (together): %d ms", CSH->th->getDiff());
|
||||
|
||||
initMapHandler();
|
||||
@@ -196,53 +197,64 @@ void CClient::newGame()
|
||||
initPlayerInterfaces();
|
||||
}
|
||||
|
||||
void CClient::loadGame()
|
||||
void CClient::loadGame(CGameState * initializedGameState)
|
||||
{
|
||||
logNetwork->info("Loading procedure started!");
|
||||
|
||||
std::unique_ptr<CLoadFile> loader;
|
||||
try
|
||||
|
||||
if(initializedGameState)
|
||||
{
|
||||
boost::filesystem::path clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(CSH->si->mapname, EResType::CLIENT_SAVEGAME));
|
||||
boost::filesystem::path controlServerSaveName;
|
||||
|
||||
if(CResourceHandler::get("local")->existsResource(ResourceID(CSH->si->mapname, EResType::SERVER_SAVEGAME)))
|
||||
{
|
||||
controlServerSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(CSH->si->mapname, EResType::SERVER_SAVEGAME));
|
||||
}
|
||||
else // create entry for server savegame. Triggered if save was made after launch and not yet present in res handler
|
||||
{
|
||||
controlServerSaveName = boost::filesystem::path(clientSaveName).replace_extension(".vsgm1");
|
||||
CResourceHandler::get("local")->createResource(controlServerSaveName.string(), true);
|
||||
}
|
||||
|
||||
if(clientSaveName.empty())
|
||||
throw std::runtime_error("Cannot open client part of " + CSH->si->mapname);
|
||||
if(controlServerSaveName.empty() || !boost::filesystem::exists(controlServerSaveName))
|
||||
throw std::runtime_error("Cannot open server part of " + CSH->si->mapname);
|
||||
|
||||
{
|
||||
CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, MINIMAL_SERIALIZATION_VERSION);
|
||||
loadCommonState(checkingLoader);
|
||||
loader = checkingLoader.decay();
|
||||
}
|
||||
|
||||
logNetwork->info("Game state was transferred over network, loading.");
|
||||
gs = initializedGameState;
|
||||
}
|
||||
catch(std::exception & e)
|
||||
else
|
||||
{
|
||||
logGlobal->error("Cannot load game %s. Error: %s", CSH->si->mapname, e.what());
|
||||
throw; //obviously we cannot continue here
|
||||
try
|
||||
{
|
||||
boost::filesystem::path clientSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(CSH->si->mapname, EResType::CLIENT_SAVEGAME));
|
||||
boost::filesystem::path controlServerSaveName;
|
||||
|
||||
if(CResourceHandler::get("local")->existsResource(ResourceID(CSH->si->mapname, EResType::SERVER_SAVEGAME)))
|
||||
{
|
||||
controlServerSaveName = *CResourceHandler::get("local")->getResourceName(ResourceID(CSH->si->mapname, EResType::SERVER_SAVEGAME));
|
||||
}
|
||||
else // create entry for server savegame. Triggered if save was made after launch and not yet present in res handler
|
||||
{
|
||||
controlServerSaveName = boost::filesystem::path(clientSaveName).replace_extension(".vsgm1");
|
||||
CResourceHandler::get("local")->createResource(controlServerSaveName.string(), true);
|
||||
}
|
||||
|
||||
if(clientSaveName.empty())
|
||||
throw std::runtime_error("Cannot open client part of " + CSH->si->mapname);
|
||||
if(controlServerSaveName.empty() || !boost::filesystem::exists(controlServerSaveName))
|
||||
throw std::runtime_error("Cannot open server part of " + CSH->si->mapname);
|
||||
|
||||
{
|
||||
CLoadIntegrityValidator checkingLoader(clientSaveName, controlServerSaveName, MINIMAL_SERIALIZATION_VERSION);
|
||||
loadCommonState(checkingLoader);
|
||||
loader = checkingLoader.decay();
|
||||
}
|
||||
}
|
||||
catch(std::exception & e)
|
||||
{
|
||||
logGlobal->error("Cannot load game %s. Error: %s", CSH->si->mapname, e.what());
|
||||
throw; //obviously we cannot continue here
|
||||
}
|
||||
logNetwork->trace("Loaded common part of save %d ms", CSH->th->getDiff());
|
||||
}
|
||||
logNetwork->trace("Loaded common part of save %d ms", CSH->th->getDiff());
|
||||
gs->preInit(VLC);
|
||||
gs->updateOnLoad(CSH->si.get());
|
||||
logNetwork->info("Game loaded, initialize interfaces.");
|
||||
|
||||
initMapHandler();
|
||||
|
||||
reinitScripting();
|
||||
|
||||
initPlayerEnvironments();
|
||||
|
||||
serialize(loader->serializer, loader->serializer.fileVersion);
|
||||
if(loader)
|
||||
serialize(loader->serializer, loader->serializer.fileVersion);
|
||||
|
||||
initPlayerInterfaces();
|
||||
}
|
||||
|
||||
@@ -150,8 +150,8 @@ public:
|
||||
vstd::CLoggerBase * logger() const override;
|
||||
events::EventBus * eventBus() const override;
|
||||
|
||||
void newGame();
|
||||
void loadGame();
|
||||
void newGame(CGameState * gameState);
|
||||
void loadGame(CGameState * gameState);
|
||||
void serialize(BinarySerializer & h, const int version);
|
||||
void serialize(BinaryDeserializer & h, const int version);
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ bool LobbyClientDisconnected::applyOnLobbyHandler(CServerHandler * handler)
|
||||
|
||||
void LobbyClientDisconnected::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
|
||||
{
|
||||
GH.popInts(1);
|
||||
if(GH.listInt.size())
|
||||
GH.popInts(1);
|
||||
}
|
||||
|
||||
void LobbyChatMessage::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
|
||||
@@ -93,25 +94,34 @@ void LobbyGuiAction::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * h
|
||||
}
|
||||
}
|
||||
|
||||
bool LobbyStartGame::applyOnLobbyHandler(CServerHandler * handler)
|
||||
bool LobbyEndGame::applyOnLobbyHandler(CServerHandler * handler)
|
||||
{
|
||||
if(handler->state == EClientState::GAMEPLAY)
|
||||
{
|
||||
handler->endGameplay(false, true);
|
||||
handler->endGameplay(closeConnection, restart);
|
||||
}
|
||||
|
||||
if(restart)
|
||||
handler->sendStartGame();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LobbyStartGame::applyOnLobbyHandler(CServerHandler * handler)
|
||||
{
|
||||
handler->state = EClientState::STARTING;
|
||||
if(handler->si->mode != StartInfo::LOAD_GAME)
|
||||
{
|
||||
handler->si = initializedStartInfo;
|
||||
}
|
||||
if(settings["session"]["headless"].Bool())
|
||||
handler->startGameplay();
|
||||
handler->startGameplay(initializedGameState);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LobbyStartGame::applyOnLobbyScreen(CLobbyScreen * lobby, CServerHandler * handler)
|
||||
{
|
||||
GH.pushIntT<CLoadingScreen>(std::bind(&CServerHandler::startGameplay, handler));
|
||||
GH.pushIntT<CLoadingScreen>(std::bind(&CServerHandler::startGameplay, handler, initializedGameState));
|
||||
}
|
||||
|
||||
bool LobbyUpdateState::applyOnLobbyHandler(CServerHandler * handler)
|
||||
|
||||
@@ -859,9 +859,6 @@ PlayerColor CStackInstance::getOwner() const
|
||||
|
||||
void CStackInstance::deserializationFix()
|
||||
{
|
||||
const CCreature *backup = type;
|
||||
type = nullptr;
|
||||
setType(backup);
|
||||
const CArmedInstance *armyBackup = _armyObj;
|
||||
_armyObj = nullptr;
|
||||
setArmyObj(armyBackup);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "HeroBonus.h"
|
||||
#include "GameConstants.h"
|
||||
#include "CArtHandler.h"
|
||||
#include "CCreatureHandler.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@@ -40,7 +41,20 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & type;
|
||||
if(h.saving)
|
||||
{
|
||||
CreatureID idNumber = type ? type->idNumber : CreatureID(CreatureID::NONE);
|
||||
h & idNumber;
|
||||
}
|
||||
else
|
||||
{
|
||||
CreatureID idNumber;
|
||||
h & idNumber;
|
||||
if(idNumber != CreatureID::NONE)
|
||||
setType(VLC->creh->objects[idNumber]);
|
||||
else
|
||||
type = nullptr;
|
||||
}
|
||||
h & count;
|
||||
}
|
||||
|
||||
|
||||
@@ -138,12 +138,29 @@ struct LobbyGuiAction : public CLobbyPackToPropagate
|
||||
}
|
||||
};
|
||||
|
||||
struct LobbyEndGame : public CLobbyPackToPropagate
|
||||
{
|
||||
bool closeConnection = false, restart = false;
|
||||
|
||||
bool checkClientPermissions(CVCMIServer * srv) const;
|
||||
bool applyOnServer(CVCMIServer * srv);
|
||||
void applyOnServerAfterAnnounce(CVCMIServer * srv);
|
||||
bool applyOnLobbyHandler(CServerHandler * handler);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & closeConnection;
|
||||
h & restart;
|
||||
}
|
||||
};
|
||||
|
||||
struct LobbyStartGame : public CLobbyPackToPropagate
|
||||
{
|
||||
// Set by server
|
||||
std::shared_ptr<StartInfo> initializedStartInfo;
|
||||
CGameState * initializedGameState;
|
||||
|
||||
LobbyStartGame() : initializedStartInfo(nullptr) {}
|
||||
LobbyStartGame() : initializedStartInfo(nullptr), initializedGameState(nullptr) {}
|
||||
bool checkClientPermissions(CVCMIServer * srv) const;
|
||||
bool applyOnServer(CVCMIServer * srv);
|
||||
void applyOnServerAfterAnnounce(CVCMIServer * srv);
|
||||
@@ -153,6 +170,10 @@ struct LobbyStartGame : public CLobbyPackToPropagate
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & initializedStartInfo;
|
||||
bool sps = h.smartPointerSerialization;
|
||||
h.smartPointerSerialization = true;
|
||||
h & initializedGameState;
|
||||
h.smartPointerSerialization = sps;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ public:
|
||||
h & players;
|
||||
h & howManyTeams;
|
||||
h & allowedHeroes;
|
||||
h & triggeredEvents;
|
||||
//Do not serialize triggeredEvents in header as they can contain information about heroes and armies
|
||||
h & victoryMessage;
|
||||
h & victoryIconIndex;
|
||||
h & defeatMessage;
|
||||
@@ -424,6 +424,7 @@ public:
|
||||
void serialize(Handler &h, const int formatVersion)
|
||||
{
|
||||
h & static_cast<CMapHeader&>(*this);
|
||||
h & triggeredEvents; //from CMapHeader
|
||||
h & rumors;
|
||||
h & allowedSpell;
|
||||
h & allowedAbilities;
|
||||
|
||||
@@ -372,6 +372,7 @@ void registerTypesLobbyPacks(Serializer &s)
|
||||
s.template registerType<CLobbyPackToPropagate, LobbyChatMessage>();
|
||||
// Only host client send
|
||||
s.template registerType<CLobbyPackToPropagate, LobbyGuiAction>();
|
||||
s.template registerType<CLobbyPackToPropagate, LobbyEndGame>();
|
||||
s.template registerType<CLobbyPackToPropagate, LobbyStartGame>();
|
||||
s.template registerType<CLobbyPackToPropagate, LobbyChangeHost>();
|
||||
// Only server send
|
||||
|
||||
@@ -220,7 +220,7 @@ void CVCMIServer::threadAnnounceLobby()
|
||||
}
|
||||
}
|
||||
|
||||
bool CVCMIServer::prepareToStartGame()
|
||||
void CVCMIServer::prepareToRestart()
|
||||
{
|
||||
if(state == EServerState::GAMEPLAY)
|
||||
{
|
||||
@@ -232,8 +232,18 @@ bool CVCMIServer::prepareToStartGame()
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
|
||||
}
|
||||
|
||||
if(!gh)
|
||||
gh = std::make_shared<CGameHandler>(this);
|
||||
for(auto c : connections)
|
||||
{
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
boost::unique_lock<boost::recursive_mutex> queueLock(mx);
|
||||
gh = nullptr;
|
||||
}
|
||||
|
||||
bool CVCMIServer::prepareToStartGame()
|
||||
{
|
||||
gh = std::make_shared<CGameHandler>(this);
|
||||
switch(si->mode)
|
||||
{
|
||||
case StartInfo::CAMPAIGN:
|
||||
|
||||
@@ -69,6 +69,7 @@ public:
|
||||
~CVCMIServer();
|
||||
void run();
|
||||
bool prepareToStartGame();
|
||||
void prepareToRestart();
|
||||
void startGameImmidiately();
|
||||
|
||||
void startAsyncAccept();
|
||||
|
||||
@@ -161,6 +161,27 @@ bool LobbyGuiAction::checkClientPermissions(CVCMIServer * srv) const
|
||||
return srv->isClientHost(c->connectionID);
|
||||
}
|
||||
|
||||
bool LobbyEndGame::checkClientPermissions(CVCMIServer * srv) const
|
||||
{
|
||||
return srv->isClientHost(c->connectionID);
|
||||
}
|
||||
|
||||
bool LobbyEndGame::applyOnServer(CVCMIServer * srv)
|
||||
{
|
||||
srv->prepareToRestart();
|
||||
return true;
|
||||
}
|
||||
|
||||
void LobbyEndGame::applyOnServerAfterAnnounce(CVCMIServer * srv)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> stateLock(srv->stateMutex);
|
||||
for(auto & c : srv->connections)
|
||||
{
|
||||
c->enterLobbyConnectionMode();
|
||||
c->disableStackSendingByID();
|
||||
}
|
||||
}
|
||||
|
||||
bool LobbyStartGame::checkClientPermissions(CVCMIServer * srv) const
|
||||
{
|
||||
return srv->isClientHost(c->connectionID);
|
||||
@@ -181,6 +202,8 @@ bool LobbyStartGame::applyOnServer(CVCMIServer * srv)
|
||||
return false;
|
||||
|
||||
initializedStartInfo = std::make_shared<StartInfo>(*srv->gh->getStartInfo(true));
|
||||
initializedGameState = srv->gh->gameState();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user