feat(config): zone_override_dir and the limits of edited zone files

World, master and chat servers read files under maps/ through the override folder
named by zone_override_dir (empty: off). The settings for who may send zone files
and how large a set may be are in sharedconfig.ini and the settings catalog.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-11-10 18:25:53 -06:00
parent f34577b5a2
commit d124372973
5 changed files with 35 additions and 0 deletions

View File

@@ -18,6 +18,7 @@
#include "MessageType/Master.h"
#include "Diagnostics.h"
#include "AssetManager.h"
#include "ZoneOverrideStore.h"
#include "BinaryPathFinder.h"
#include "ServiceType.h"
#include "PlayerContainer.h"
@@ -92,6 +93,8 @@ int main(int argc, char** argv) {
}
Game::assetManager = new AssetManager(clientPath);
// Edited zone files are read in place of the client's (docs/ZonePublish.md)
Game::assetManager->SetOverrideDir(ZoneOverrideStore::RootFromSetting(Game::config->GetValue("zone_override_dir")));
} catch (std::runtime_error& ex) {
LOG("Got an error while setting up assets: %s", ex.what());
delete Game::logger;

View File

@@ -152,6 +152,16 @@ namespace {
c.Add(Unit(Int(MASTER, "live_update_service_timeout", "Server restart timeout", "How long auth, chat, the UGC server or the dashboard may take to stop or come back before master starts it again (3 tries).", "30", 10, 600), "seconds"));
c.Add(Bool(MASTER, "live_update_run_migrations", "Run database migrations", "Run the new build's database migrations first. The running servers must cope with the new schema until they are replaced.", true));
c.AddSection("Edited zone files", "Zone files sent by an external level editor through the dashboard's API (docs/ZonePublish.md): they are kept in their own folder and read in place of the client's, which are never written.");
c.Add(Format(Text(SHARED, "zone_override_dir", "Override folder", "A file under maps/ is read from this folder's maps/ when it is there, and from the client otherwise. Also holds the sets being checked and the replaced sets. Relative to the server binaries unless absolute. Empty turns the feature off.", "", true), eFormat::PATH));
c.Add(Int(SHARED, "zone_publish_gm_level", "Level to send zone files", "The lowest GM level that may send, restore or clear a zone's edited files. The account also has to hold the zone's lock, and its API key needs the zones.publish permission.", "9", 1, 9));
c.Add(Int(SHARED, "zone_lock_admin_gm_level", "Level to manage zone locks", "The lowest GM level that may take any zone's lock without being one of its editors, take a lock away from its holder, and assign editors.", "9", 1, 9));
c.Add(Unit(Int(SHARED, "zone_publish_max_file_mb", "Largest file", "The largest single file of a set.", "64", 1, 1024), "MiB"));
c.Add(Unit(Int(SHARED, "zone_publish_max_total_mb", "Largest set", "The largest set, all its files together.", "256", 1, 4096), "MiB"));
c.Add(Int(SHARED, "zone_publish_max_files", "Files in a set", "The most files one set can have.", "128", 1, 1024));
c.Add(Int(SHARED, "zone_publish_max_objects", "Objects in a set", "The most objects the scenes of one set can place, all together.", "100000", 1, 10000000));
c.Add(Int(SHARED, "zone_publish_max_backups", "Replaced sets kept", "How many of a zone's replaced sets are kept to go back to; older ones are deleted.", "20", 0, 1000));
c.AddSection("Game client");
c.Add(Format(Text(SHARED, "client_location", "Client folder", "The folder with res/, or the one with client/ and versions/.", "", true), eFormat::PATH));
c.Add(Int(SHARED, "client_net_version", "Network version", "Clients reporting another version are refused. 171022 for the retail client, 171023 for Darkflame Universe clients.", "171022", 0, std::nullopt, true));

View File

@@ -29,6 +29,7 @@
#include "Logger.h"
#include "dServer.h"
#include "AssetManager.h"
#include "ZoneOverrideStore.h"
#include "BinaryPathFinder.h"
#include "ServiceType.h"
#include "MessageType/Master.h"
@@ -313,6 +314,8 @@ int main(int argc, char** argv) {
}
Game::assetManager = new AssetManager(clientPath);
// Edited zone files are read in place of the client's (docs/ZonePublish.md)
Game::assetManager->SetOverrideDir(ZoneOverrideStore::RootFromSetting(Game::config->GetValue("zone_override_dir")));
} catch (std::runtime_error& ex) {
LOG("Got an error while setting up assets: %s", ex.what());
LOG("Is the provided client_location in Windows Onedrive? If so, remove it from Onedrive.");

View File

@@ -88,6 +88,7 @@
#include "PropertyManagementComponent.h"
#include "EditMode.h"
#include "AssetManager.h"
#include "ZoneOverrideStore.h"
#include "LevelProgressionComponent.h"
#include "eBlueprintSaveResponseType.h"
#include "Amf3.h"
@@ -289,6 +290,8 @@ int main(int argc, char** argv) {
clientPath = BinaryPathFinder::GetBinaryDir() / clientPath;
}
Game::assetManager = new AssetManager(clientPath);
// Edited zone files are read in place of the client's (docs/ZonePublish.md)
Game::assetManager->SetOverrideDir(ZoneOverrideStore::RootFromSetting(Game::config->GetValue("zone_override_dir")));
} catch (const std::exception& ex) {
LOG("Got an error while setting up assets: %s", ex.what());

View File

@@ -130,3 +130,19 @@ replay_sandbox=0
# Live database (sandbox): Set by the capture tool in replay sandboxes: the real server's SQLite file, which a sandbox
# refuses to open. Read when the server starts.
replay_live_sqlite_path=
# Edited zone files (docs/ZonePublish.md). A folder for zone files sent by an external level editor: a file under
# maps/ is read from <zone_override_dir>/maps/... when it is there, and from the client otherwise. The client's own
# files are never written. Relative to the servers' folder unless absolute. Empty = off.
zone_override_dir=
# The lowest GM level that may send, restore or clear a zone's edited files (the account also has to hold the zone's lock)
zone_publish_gm_level=9
# The lowest GM level that may take any zone's lock without being one of its editors, take a lock away, and assign editors
zone_lock_admin_gm_level=9
# Limits of one set of edited zone files: megabytes per file, megabytes and files per set, objects in its scenes
zone_publish_max_file_mb=64
zone_publish_max_total_mb=256
zone_publish_max_files=128
zone_publish_max_objects=100000
# How many replaced sets are kept per zone to go back to
zone_publish_max_backups=20