Separating state out of the location

This commit is contained in:
Vladislav Khorev committed 2026-10-30 14:56:24 +06:00
1 parent 5e9a663812
commit 297bd7377f
45 files changed
+2114 -778

No files matched your search

+22 -19
View File
@@ -79,12 +79,13 @@ namespace FRG
Location* Game::currentLocation() const {
const auto state = stateSnapshot();
if (!state || state->currentLocationId.empty()) return nullptr;
return internalGameServer.runtimeLocation(state->currentLocationId);
return gameServerHost.runtimeLocation(state->currentLocationId);
}
Game::Game()
: audioPlayer(std::make_unique<AudioPlayerAsync>())
, internalGameServer()
, gameServerHost(internalGameServer)
, menuManager(renderer, internalGameServer, *audioPlayer)
, newTickCount(0)
, lastTickCount(0)
@@ -505,7 +506,7 @@ namespace FRG
bool Game::isLocationLoaded(const std::string& campaignId, const std::string& locationId) const {
return player && loadedCampaignId == campaignId
&& internalGameServer.hasRuntimeLocation(locationId);
&& gameServerHost.hasRuntimeLocation(locationId);
}
void Game::enterLocationThen(const std::string& requestedCampaignId, const std::string& requestedLocationId,
@@ -548,7 +549,7 @@ namespace FRG
const CampaignConfig* campaign =
CampaignRegistry::instance().find(campaignId);
if (!campaign) return;
internalGameServer.initializeCampaign(
gameServerHost.initializeCampaign(
campaignId, campaign->questsPath, CONST_ZIP_FILE);
// The player stays loaded for the whole campaign; locations come and go around him.
player = Location::createPlayer(
@@ -562,7 +563,7 @@ namespace FRG
unloadLocation(false);
player.reset();
loadedCampaignId.clear();
internalGameServer.clearCampaign();
gameServerHost.clearCampaign();
renderer.textureManager.UnloadUnused(); // the player's textures
}
@@ -575,18 +576,19 @@ namespace FRG
<< locationId << "'" << std::endl;
return;
}
const bool initializeLocation = internalGameServer.prepareLocation(*config);
SDL_PumpEvents();
const bool initializeLocation = gameServerHost.prepareLocation(*config);
std::shared_ptr<Location> loc = createLocation(*config);
wireLocation(loc.get());
if (shadowMap) loc->shadowMap = shadowMap;
if (initializeLocation)
loc->scriptEngine.callLocationInitCallback();
// Back to how the player left it (or to the start state's snapshot of it).
internalGameServer.bindRuntimeLocation(locationId, loc);
gameServerHost.bindRuntimeLocation(locationId, loc);
}
void Game::unloadLocation(bool storeState) {
internalGameServer.clearRuntimeLocations(storeState);
gameServerHost.clearRuntimeLocations(storeState);
// Textures only the location's models and characters used are freed now.
renderer.textureManager.UnloadUnused();
}
@@ -639,8 +641,8 @@ namespace FRG
// Rebuild the loaded location from its config; the others have no stored state
// any more, so they are built fresh when the player first goes there.
std::vector<std::string> loadedIds =
internalGameServer.loadedRuntimeLocationIds();
internalGameServer.resetCampaign(
gameServerHost.loadedRuntimeLocationIds();
gameServerHost.resetCampaign(
activeCampaign().questsPath, CONST_ZIP_FILE);
unloadLocation(false);
for (const std::string& id : loadedIds) loadLocation(id);
@@ -649,6 +651,7 @@ namespace FRG
// from this freshly-rebuilt state after changing gameplay/content JSON or Lua.
// Re-comment before shipping.
//saveInitialState();
}
void Game::performResetToInitialState() {
@@ -671,7 +674,7 @@ namespace FRG
if (!content.empty()) {
try {
nlohmann::json root = nlohmann::json::parse(content);
internalGameServer.load(root); // applies to the loaded location in place and stores
gameServerHost.load(root); // applies to the loaded location in place and stores
// the other locations' states for when they load.
return;
} catch (const std::exception& e) {
@@ -696,7 +699,7 @@ namespace FRG
void Game::saveInitialState() {
nlohmann::json root;
internalGameServer.save(root);
gameServerHost.save(root);
// Written next to the executable; copy it over the campaign's start-state file.
const std::string startStatePath = activeCampaign().startStatePath;
const std::string path = startStatePath.substr(startStatePath.find_last_of('/') + 1);
@@ -729,7 +732,7 @@ namespace FRG
auto loc = std::make_shared<Location>(
renderer, internalGameServer, config.id);
internalGameServer.setupRuntimeLocation(
gameServerHost.setupRuntimeLocation(
config.id, loc, std::move(params), audioPlayer.get());
loc->requestNightDayTransition = [this](bool isNight, bool isDawn) {
const auto state = stateSnapshot();
@@ -861,8 +864,8 @@ namespace FRG
CheckGlError(__FILE__, __LINE__);
logger() << "Shadow map initialized" << std::endl;
for (const std::string& id : internalGameServer.loadedRuntimeLocationIds())
if (Location* loc = internalGameServer.runtimeLocation(id))
for (const std::string& id : gameServerHost.loadedRuntimeLocationIds())
if (Location* loc = gameServerHost.runtimeLocation(id))
loc->shadowMap = shadowMap;
}
@@ -873,8 +876,8 @@ namespace FRG
shadowMap.reset();
CheckGlError(__FILE__, __LINE__);
for (const std::string& id : internalGameServer.loadedRuntimeLocationIds())
if (Location* loc = internalGameServer.runtimeLocation(id))
for (const std::string& id : gameServerHost.loadedRuntimeLocationIds())
if (Location* loc = gameServerHost.runtimeLocation(id))
loc->shadowMap.reset();
CheckGlError(__FILE__, __LINE__);
@@ -1135,7 +1138,7 @@ namespace FRG
{
// The authoritative implementation advances simulation; a future
// network client can use the same call to poll/apply server updates.
internalGameServer.update(delta);
gameServerHost.update(delta);
processServerEvents();
}
@@ -1882,7 +1885,7 @@ namespace FRG
void Game::saveGame(int slot)
{
nlohmann::json root;
internalGameServer.save(root);
gameServerHost.save(root);
std::string path = "save_slot" + std::to_string(slot) + ".json";
/*std::ofstream file(path);
@@ -1922,7 +1925,7 @@ namespace FRG
return;
}
enterLocationThen(campaignId, locationId, [this, root]() {
internalGameServer.load(root);
gameServerHost.load(root);
playMusicForLoadedGame();
menuManager.enterGameplay(true);
});