From 31bfb7e428edfb05828d7e450a68516475021356 Mon Sep 17 00:00:00 2001 From: kuwacom Date: Sat, 7 Mar 2026 01:21:04 +0900 Subject: [PATCH] update: add basically all configuration options that are implemented in the classes to `server.properties` --- Minecraft.Server/ServerProperties.cpp | 425 +++++++++++++++++++++- Minecraft.Server/ServerProperties.h | 53 +++ Minecraft.Server/Windows64/ServerMain.cpp | 106 ++++-- 3 files changed, 538 insertions(+), 46 deletions(-) diff --git a/Minecraft.Server/ServerProperties.cpp b/Minecraft.Server/ServerProperties.cpp index bd0d44cf6..47b2aa058 100644 --- a/Minecraft.Server/ServerProperties.cpp +++ b/Minecraft.Server/ServerProperties.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace ServerRuntime @@ -21,19 +22,52 @@ struct ServerPropertyDefault static const char *kServerPropertiesPath = "server.properties"; static const size_t kMaxSaveIdLength = 31; +static const int kDefaultServerPort = 25565; +static const int kDefaultMaxPlayers = 8; +static const int kMaxDedicatedPlayers = 8; +static const int kDefaultAutosaveIntervalSeconds = 60; + static const ServerPropertyDefault kServerPropertyDefaults[] = { - { "level-name", "world" }, - { "level-id", "world" }, - { "level-type", "default" }, + { "allow-flight", "true" }, + { "allow-nether", "true" }, + { "autosave-interval", "60" }, + { "bedrock-fog", "true" }, + { "bonus-chest", "false" }, + { "difficulty", "1" }, + { "disable-saving", "false" }, + { "do-daylight-cycle", "true" }, + { "do-mob-loot", "true" }, + { "do-mob-spawning", "true" }, + { "do-tile-drops", "true" }, + { "fire-spreads", "true" }, + { "friends-of-friends", "false" }, { "gamemode", "0" }, + { "gamertags", "true" }, + { "generate-structures", "true" }, + { "host-can-be-invisible", "true" }, + { "host-can-change-hunger", "true" }, + { "host-can-fly", "true" }, + { "keep-inventory", "false" }, + { "level-id", "world" }, + { "level-name", "world" }, + { "level-seed", "" }, + { "level-type", "default" }, + { "log-level", "info" }, { "max-build-height", "256" }, - { "spawn-animals", "true" }, - { "spawn-npcs", "true" }, - { "spawn-monsters", "true" }, + { "max-players", "8" }, + { "mob-griefing", "true" }, + { "motd", "A Minecraft Server" }, + { "natural-regeneration", "true" }, { "pvp", "true" }, - { "server-ip", "" }, - { "motd", "A Minecraft Server" } + { "server-ip", "0.0.0.0" }, + { "server-name", "DedicatedServer" }, + { "server-port", "25565" }, + { "spawn-animals", "true" }, + { "spawn-monsters", "true" }, + { "spawn-npcs", "true" }, + { "tnt", "true" }, + { "trust-players", "true" } }; static std::string TrimAscii(const std::string &value) @@ -53,6 +87,134 @@ static std::string TrimAscii(const std::string &value) return value.substr(start, end - start); } +static std::string ToLowerAscii(const std::string &value) +{ + std::string lowered = value; + for (size_t i = 0; i < lowered.length(); ++i) + { + unsigned char ch = (unsigned char)lowered[i]; + lowered[i] = (char)std::tolower(ch); + } + return lowered; +} + +static std::string BoolToString(bool value) +{ + return value ? "true" : "false"; +} + +static std::string IntToString(int value) +{ + char buffer[32] = {}; + sprintf_s(buffer, sizeof(buffer), "%d", value); + return std::string(buffer); +} + +static std::string Int64ToString(__int64 value) +{ + char buffer[64] = {}; + _i64toa_s(value, buffer, sizeof(buffer), 10); + return std::string(buffer); +} + +static int ClampInt(int value, int minValue, int maxValue) +{ + if (value < minValue) + { + return minValue; + } + if (value > maxValue) + { + return maxValue; + } + return value; +} + +static bool TryParseBool(const std::string &value, bool *outValue) +{ + if (outValue == NULL) + { + return false; + } + + std::string lowered = ToLowerAscii(TrimAscii(value)); + if (lowered == "true" || lowered == "1" || lowered == "yes" || lowered == "on") + { + *outValue = true; + return true; + } + if (lowered == "false" || lowered == "0" || lowered == "no" || lowered == "off") + { + *outValue = false; + return true; + } + return false; +} + +static bool TryParseInt(const std::string &value, int *outValue) +{ + if (outValue == NULL) + { + return false; + } + + std::string trimmed = TrimAscii(value); + if (trimmed.empty()) + { + return false; + } + + char *end = NULL; + long parsed = strtol(trimmed.c_str(), &end, 10); + if (end == trimmed.c_str() || *end != 0) + { + return false; + } + + *outValue = (int)parsed; + return true; +} + +static bool TryParseInt64(const std::string &value, __int64 *outValue) +{ + if (outValue == NULL) + { + return false; + } + + std::string trimmed = TrimAscii(value); + if (trimmed.empty()) + { + return false; + } + + char *end = NULL; + __int64 parsed = _strtoi64(trimmed.c_str(), &end, 10); + if (end == trimmed.c_str() || *end != 0) + { + return false; + } + + *outValue = parsed; + return true; +} + +static std::string LogLevelToPropertyValue(EServerLogLevel level) +{ + switch (level) + { + case eServerLogLevel_Debug: + return "debug"; + case eServerLogLevel_Warn: + return "warn"; + case eServerLogLevel_Error: + return "error"; + case eServerLogLevel_Info: + default: + return "info"; + } +} + /** * 任意文字列を保存先IDとして安全な形式に正規化する * @@ -222,7 +384,7 @@ static bool WriteServerPropertiesFile(const char *filePath, const std::unordered } fprintf(outFile, "# Minecraft server properties\n"); - fprintf(outFile, "# Auto-generated when missing\n"); + fprintf(outFile, "# Auto-generated and normalized when missing\n"); std::map sortedProperties(properties.begin(), properties.end()); for (std::map::const_iterator it = sortedProperties.begin(); it != sortedProperties.end(); ++it) @@ -234,6 +396,203 @@ static bool WriteServerPropertiesFile(const char *filePath, const std::unordered return true; } +static bool ReadNormalizedBoolProperty( + std::unordered_map *properties, + const char *key, + bool defaultValue, + bool *shouldWrite) +{ + std::string raw = TrimAscii((*properties)[key]); + bool value = defaultValue; + if (!TryParseBool(raw, &value)) + { + value = defaultValue; + } + + std::string normalized = BoolToString(value); + if (raw != normalized) + { + (*properties)[key] = normalized; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + + return value; +} + +static int ReadNormalizedIntProperty( + std::unordered_map *properties, + const char *key, + int defaultValue, + int minValue, + int maxValue, + bool *shouldWrite) +{ + std::string raw = TrimAscii((*properties)[key]); + int value = defaultValue; + if (!TryParseInt(raw, &value)) + { + value = defaultValue; + } + value = ClampInt(value, minValue, maxValue); + + std::string normalized = IntToString(value); + if (raw != normalized) + { + (*properties)[key] = normalized; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + + return value; +} + +static std::string ReadNormalizedStringProperty( + std::unordered_map *properties, + const char *key, + const std::string &defaultValue, + size_t maxLength, + bool *shouldWrite) +{ + std::string value = TrimAscii((*properties)[key]); + if (value.empty()) + { + value = defaultValue; + } + if (maxLength > 0 && value.length() > maxLength) + { + value.resize(maxLength); + } + + if (value != (*properties)[key]) + { + (*properties)[key] = value; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + + return value; +} + +static bool ReadNormalizedOptionalInt64Property( + std::unordered_map *properties, + const char *key, + __int64 *outValue, + bool *shouldWrite) +{ + std::string raw = TrimAscii((*properties)[key]); + if (raw.empty()) + { + if ((*properties)[key] != "") + { + (*properties)[key] = ""; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + return false; + } + + __int64 parsed = 0; + if (!TryParseInt64(raw, &parsed)) + { + (*properties)[key] = ""; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + return false; + } + + std::string normalized = Int64ToString(parsed); + if (raw != normalized) + { + (*properties)[key] = normalized; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + + if (outValue != NULL) + { + *outValue = parsed; + } + return true; +} + +static EServerLogLevel ReadNormalizedLogLevelProperty( + std::unordered_map *properties, + const char *key, + EServerLogLevel defaultValue, + bool *shouldWrite) +{ + std::string raw = TrimAscii((*properties)[key]); + EServerLogLevel value = defaultValue; + if (!TryParseServerLogLevel(raw.c_str(), &value)) + { + value = defaultValue; + } + + std::string normalized = LogLevelToPropertyValue(value); + if (raw != normalized) + { + (*properties)[key] = normalized; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + + return value; +} + +static std::string ReadNormalizedLevelTypeProperty( + std::unordered_map *properties, + const char *key, + bool *outIsFlat, + bool *shouldWrite) +{ + std::string raw = TrimAscii((*properties)[key]); + std::string lowered = ToLowerAscii(raw); + + bool isFlat = false; + std::string normalized = "default"; + if (lowered == "flat" || lowered == "superflat" || lowered == "1") + { + isFlat = true; + normalized = "flat"; + } + else if (lowered == "default" || lowered == "normal" || lowered == "0") + { + isFlat = false; + normalized = "default"; + } + + if (raw != normalized) + { + (*properties)[key] = normalized; + if (shouldWrite != NULL) + { + *shouldWrite = true; + } + } + + if (outIsFlat != NULL) + { + *outIsFlat = isFlat; + } + + return normalized; +} + /** * 実効的なワールド設定を読み込み、欠損/不正を補正して返す * @@ -313,6 +672,50 @@ ServerPropertiesConfig LoadServerPropertiesConfig() merged["level-name"] = worldName; merged["level-id"] = worldSaveId; + config.worldName = Utf8ToWide(worldName.c_str()); + config.worldSaveId = worldSaveId; + + config.serverPort = ReadNormalizedIntProperty(&merged, "server-port", kDefaultServerPort, 1, 65535, &shouldWrite); + config.serverIp = ReadNormalizedStringProperty(&merged, "server-ip", "0.0.0.0", 255, &shouldWrite); + config.serverName = ReadNormalizedStringProperty(&merged, "server-name", "DedicatedServer", 16, &shouldWrite); + config.maxPlayers = ReadNormalizedIntProperty(&merged, "max-players", kDefaultMaxPlayers, 1, kMaxDedicatedPlayers, &shouldWrite); + config.seed = 0; + config.hasSeed = ReadNormalizedOptionalInt64Property(&merged, "level-seed", &config.seed, &shouldWrite); + config.logLevel = ReadNormalizedLogLevelProperty(&merged, "log-level", eServerLogLevel_Info, &shouldWrite); + config.autosaveIntervalSeconds = ReadNormalizedIntProperty(&merged, "autosave-interval", kDefaultAutosaveIntervalSeconds, 5, 3600, &shouldWrite); + + config.difficulty = ReadNormalizedIntProperty(&merged, "difficulty", 1, 0, 3, &shouldWrite); + config.gameMode = ReadNormalizedIntProperty(&merged, "gamemode", 0, 0, 1, &shouldWrite); + config.levelType = ReadNormalizedLevelTypeProperty(&merged, "level-type", &config.levelTypeFlat, &shouldWrite); + config.generateStructures = ReadNormalizedBoolProperty(&merged, "generate-structures", true, &shouldWrite); + config.bonusChest = ReadNormalizedBoolProperty(&merged, "bonus-chest", false, &shouldWrite); + config.pvp = ReadNormalizedBoolProperty(&merged, "pvp", true, &shouldWrite); + config.trustPlayers = ReadNormalizedBoolProperty(&merged, "trust-players", true, &shouldWrite); + config.fireSpreads = ReadNormalizedBoolProperty(&merged, "fire-spreads", true, &shouldWrite); + config.tnt = ReadNormalizedBoolProperty(&merged, "tnt", true, &shouldWrite); + config.spawnAnimals = ReadNormalizedBoolProperty(&merged, "spawn-animals", true, &shouldWrite); + config.spawnNpcs = ReadNormalizedBoolProperty(&merged, "spawn-npcs", true, &shouldWrite); + config.spawnMonsters = ReadNormalizedBoolProperty(&merged, "spawn-monsters", true, &shouldWrite); + config.allowFlight = ReadNormalizedBoolProperty(&merged, "allow-flight", true, &shouldWrite); + config.allowNether = ReadNormalizedBoolProperty(&merged, "allow-nether", true, &shouldWrite); + config.friendsOfFriends = ReadNormalizedBoolProperty(&merged, "friends-of-friends", false, &shouldWrite); + config.gamertags = ReadNormalizedBoolProperty(&merged, "gamertags", true, &shouldWrite); + config.bedrockFog = ReadNormalizedBoolProperty(&merged, "bedrock-fog", true, &shouldWrite); + config.hostCanFly = ReadNormalizedBoolProperty(&merged, "host-can-fly", true, &shouldWrite); + config.hostCanChangeHunger = ReadNormalizedBoolProperty(&merged, "host-can-change-hunger", true, &shouldWrite); + config.hostCanBeInvisible = ReadNormalizedBoolProperty(&merged, "host-can-be-invisible", true, &shouldWrite); + config.disableSaving = ReadNormalizedBoolProperty(&merged, "disable-saving", false, &shouldWrite); + config.mobGriefing = ReadNormalizedBoolProperty(&merged, "mob-griefing", true, &shouldWrite); + config.keepInventory = ReadNormalizedBoolProperty(&merged, "keep-inventory", false, &shouldWrite); + config.doMobSpawning = ReadNormalizedBoolProperty(&merged, "do-mob-spawning", true, &shouldWrite); + config.doMobLoot = ReadNormalizedBoolProperty(&merged, "do-mob-loot", true, &shouldWrite); + config.doTileDrops = ReadNormalizedBoolProperty(&merged, "do-tile-drops", true, &shouldWrite); + config.naturalRegeneration = ReadNormalizedBoolProperty(&merged, "natural-regeneration", true, &shouldWrite); + config.doDaylightCycle = ReadNormalizedBoolProperty(&merged, "do-daylight-cycle", true, &shouldWrite); + + config.maxBuildHeight = ReadNormalizedIntProperty(&merged, "max-build-height", 256, 64, 256, &shouldWrite); + config.motd = ReadNormalizedStringProperty(&merged, "motd", "A Minecraft Server", 255, &shouldWrite); + if (shouldWrite) { if (WriteServerPropertiesFile(kServerPropertiesPath, merged)) @@ -325,8 +728,6 @@ ServerPropertiesConfig LoadServerPropertiesConfig() } } - config.worldName = Utf8ToWide(worldName.c_str()); - config.worldSaveId = worldSaveId; return config; } @@ -355,7 +756,7 @@ bool SaveServerPropertiesConfig(const ServerPropertiesConfig &config) std::string worldName = TrimAscii(WideToUtf8(config.worldName)); if (worldName.empty()) { - worldName = "world"; // フォルト名 + worldName = "world"; // デフォルト名 } std::string worldSaveId = TrimAscii(config.worldSaveId); diff --git a/Minecraft.Server/ServerProperties.h b/Minecraft.Server/ServerProperties.h index 9c009f1d3..5e93abd31 100644 --- a/Minecraft.Server/ServerProperties.h +++ b/Minecraft.Server/ServerProperties.h @@ -1,6 +1,7 @@ #pragma once #include +#include "ServerLogger.h" namespace ServerRuntime { @@ -13,6 +14,58 @@ namespace ServerRuntime std::wstring worldName; /** world save id `level-id` */ std::string worldSaveId; + + /** `server-port` */ + int serverPort; + /** `server-ip` */ + std::string serverIp; + /** `server-name` (max 16 chars at runtime) */ + std::string serverName; + /** `max-players` */ + int maxPlayers; + /** `level-seed` is explicitly set */ + bool hasSeed; + /** `level-seed` */ + __int64 seed; + /** `log-level` */ + EServerLogLevel logLevel; + /** `autosave-interval` (seconds) */ + int autosaveIntervalSeconds; + + /** host options / game settings */ + int difficulty; + int gameMode; + bool levelTypeFlat; + bool generateStructures; + bool bonusChest; + bool pvp; + bool trustPlayers; + bool fireSpreads; + bool tnt; + bool spawnAnimals; + bool spawnNpcs; + bool spawnMonsters; + bool allowFlight; + bool allowNether; + bool friendsOfFriends; + bool gamertags; + bool bedrockFog; + bool hostCanFly; + bool hostCanChangeHunger; + bool hostCanBeInvisible; + bool disableSaving; + bool mobGriefing; + bool keepInventory; + bool doMobSpawning; + bool doMobLoot; + bool doTileDrops; + bool naturalRegeneration; + bool doDaylightCycle; + + /** other MinecraftServer runtime settings */ + int maxBuildHeight; + std::string levelType; + std::string motd; }; /** diff --git a/Minecraft.Server/Windows64/ServerMain.cpp b/Minecraft.Server/Windows64/ServerMain.cpp index 86af283b3..a0cd3be28 100644 --- a/Minecraft.Server/Windows64/ServerMain.cpp +++ b/Minecraft.Server/Windows64/ServerMain.cpp @@ -5,7 +5,6 @@ #include "Input.h" #include "Minecraft.h" #include "MinecraftServer.h" -#include "Options.h" #include "..\ServerLogger.h" #include "..\ServerProperties.h" #include "..\WorldManager.h" @@ -62,7 +61,7 @@ struct DedicatedServerConfig }; static volatile bool g_shutdownRequested = false; -static const DWORD kAutosaveIntervalMs = 60 * 1000; +static const DWORD kDefaultAutosaveIntervalMs = 60 * 1000; static const int kServerActionPad = 0; static BOOL WINAPI ConsoleCtrlHandlerProc(DWORD ctrlType) @@ -98,13 +97,13 @@ static int WaitForServerStoppedThreadProc(void *) static void PrintUsage() { ServerRuntime::LogInfo("usage", "Minecraft.Server.exe [options]"); - ServerRuntime::LogInfo("usage", " -port <1-65535> Listen TCP port (default: 25565)"); - ServerRuntime::LogInfo("usage", " -ip Bind address (default: 0.0.0.0)"); + ServerRuntime::LogInfo("usage", " -port <1-65535> Listen TCP port (default: server.properties:server-port)"); + ServerRuntime::LogInfo("usage", " -ip Bind address (default: server.properties:server-ip)"); ServerRuntime::LogInfo("usage", " -bind Alias of -ip"); - ServerRuntime::LogInfo("usage", " -name Host display name (max 16 chars)"); - ServerRuntime::LogInfo("usage", " -maxplayers <1-8> Public slots (default: 8)"); - ServerRuntime::LogInfo("usage", " -seed World seed"); - ServerRuntime::LogInfo("usage", " -loglevel debug|info|warn|error (default: info)"); + ServerRuntime::LogInfo("usage", " -name Host display name (max 16 chars, default: server.properties:server-name)"); + ServerRuntime::LogInfo("usage", " -maxplayers <1-8> Public slots (default: server.properties:max-players)"); + ServerRuntime::LogInfo("usage", " -seed World seed (overrides server.properties:level-seed)"); + ServerRuntime::LogInfo("usage", " -loglevel debug|info|warn|error (default: server.properties:log-level)"); ServerRuntime::LogInfo("usage", " -help Show this help"); } @@ -232,6 +231,30 @@ static void SetExeWorkingDirectory() } } +static void ApplyServerPropertiesToDedicatedConfig(const ServerPropertiesConfig &serverProperties, DedicatedServerConfig *config) +{ + if (config == NULL) + { + return; + } + + config->port = serverProperties.serverPort; + strncpy_s( + config->bindIP, + sizeof(config->bindIP), + serverProperties.serverIp.empty() ? "0.0.0.0" : serverProperties.serverIp.c_str(), + _TRUNCATE); + strncpy_s( + config->name, + sizeof(config->name), + serverProperties.serverName.empty() ? "DedicatedServer" : serverProperties.serverName.c_str(), + _TRUNCATE); + config->maxPlayers = serverProperties.maxPlayers; + config->logLevel = serverProperties.logLevel; + config->hasSeed = serverProperties.hasSeed; + config->seed = serverProperties.seed; +} + /** * 非同期処理進行に必須なコアサブシステムを1フレーム分進める * @@ -274,6 +297,13 @@ int main(int argc, char **argv) config.hasSeed = false; config.showHelp = false; + SetConsoleCtrlHandler(ConsoleCtrlHandlerProc, TRUE); + SetExeWorkingDirectory(); + + // server.properties の値をベース設定として読み込み、CLI で必要に応じて上書きする + ServerPropertiesConfig serverProperties = LoadServerPropertiesConfig(); + ApplyServerPropertiesToDedicatedConfig(serverProperties, &config); + if (!ParseCommandLine(argc, argv, &config)) { PrintUsage(); @@ -287,8 +317,6 @@ int main(int argc, char **argv) SetServerLogLevel(config.logLevel); LogStartupStep("initializing process state"); - SetConsoleCtrlHandler(ConsoleCtrlHandlerProc, TRUE); - SetExeWorkingDirectory(); g_iScreenWidth = 1280; g_iScreenHeight = 720; @@ -378,35 +406,40 @@ int main(int argc, char **argv) } app.InitGameSettings(); - if (minecraft->options != NULL) - { - minecraft->options->set(Options::Option::MUSIC, 0.0f); - minecraft->options->set(Options::Option::SOUND, 0.0f); - } MinecraftServer::resetFlags(); app.SetTutorialMode(false); app.SetCorruptSaveDeleted(false); - app.SetGameHostOption(eGameHostOption_Difficulty, 1); - app.SetGameHostOption(eGameHostOption_FriendsOfFriends, 0); - app.SetGameHostOption(eGameHostOption_Gamertags, 1); - app.SetGameHostOption(eGameHostOption_BedrockFog, 1); - app.SetGameHostOption(eGameHostOption_GameType, 0); - app.SetGameHostOption(eGameHostOption_LevelType, 0); - app.SetGameHostOption(eGameHostOption_Structures, 1); - app.SetGameHostOption(eGameHostOption_BonusChest, 0); - app.SetGameHostOption(eGameHostOption_PvP, 1); - app.SetGameHostOption(eGameHostOption_TrustPlayers, 1); - app.SetGameHostOption(eGameHostOption_FireSpreads, 1); - app.SetGameHostOption(eGameHostOption_TNT, 1); - app.SetGameHostOption(eGameHostOption_HostCanFly, 1); - app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, 1); - app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, 1); + app.SetGameHostOption(eGameHostOption_Difficulty, serverProperties.difficulty); + app.SetGameHostOption(eGameHostOption_FriendsOfFriends, serverProperties.friendsOfFriends ? 1 : 0); + app.SetGameHostOption(eGameHostOption_Gamertags, serverProperties.gamertags ? 1 : 0); + app.SetGameHostOption(eGameHostOption_BedrockFog, serverProperties.bedrockFog ? 1 : 0); + app.SetGameHostOption(eGameHostOption_GameType, serverProperties.gameMode); + app.SetGameHostOption(eGameHostOption_LevelType, serverProperties.levelTypeFlat ? 1 : 0); + app.SetGameHostOption(eGameHostOption_Structures, serverProperties.generateStructures ? 1 : 0); + app.SetGameHostOption(eGameHostOption_BonusChest, serverProperties.bonusChest ? 1 : 0); + app.SetGameHostOption(eGameHostOption_PvP, serverProperties.pvp ? 1 : 0); + app.SetGameHostOption(eGameHostOption_TrustPlayers, serverProperties.trustPlayers ? 1 : 0); + app.SetGameHostOption(eGameHostOption_FireSpreads, serverProperties.fireSpreads ? 1 : 0); + app.SetGameHostOption(eGameHostOption_TNT, serverProperties.tnt ? 1 : 0); + app.SetGameHostOption( + eGameHostOption_CheatsEnabled, + (serverProperties.hostCanFly || serverProperties.hostCanChangeHunger || serverProperties.hostCanBeInvisible) ? 1 : 0); + app.SetGameHostOption(eGameHostOption_HostCanFly, serverProperties.hostCanFly ? 1 : 0); + app.SetGameHostOption(eGameHostOption_HostCanChangeHunger, serverProperties.hostCanChangeHunger ? 1 : 0); + app.SetGameHostOption(eGameHostOption_HostCanBeInvisible, serverProperties.hostCanBeInvisible ? 1 : 0); + app.SetGameHostOption(eGameHostOption_DisableSaving, serverProperties.disableSaving ? 1 : 0); + app.SetGameHostOption(eGameHostOption_MobGriefing, serverProperties.mobGriefing ? 1 : 0); + app.SetGameHostOption(eGameHostOption_KeepInventory, serverProperties.keepInventory ? 1 : 0); + app.SetGameHostOption(eGameHostOption_DoMobSpawning, serverProperties.doMobSpawning ? 1 : 0); + app.SetGameHostOption(eGameHostOption_DoMobLoot, serverProperties.doMobLoot ? 1 : 0); + app.SetGameHostOption(eGameHostOption_DoTileDrops, serverProperties.doTileDrops ? 1 : 0); + app.SetGameHostOption(eGameHostOption_NaturalRegeneration, serverProperties.naturalRegeneration ? 1 : 0); + app.SetGameHostOption(eGameHostOption_DoDaylightCycle, serverProperties.doDaylightCycle ? 1 : 0); - StorageManager.SetSaveDisabled(false); + StorageManager.SetSaveDisabled(serverProperties.disableSaving); // server.properties から world 名と固定 save-id を取得し、 // WorldManager にロード/新規作成判定を委譲する - ServerPropertiesConfig serverProperties = LoadServerPropertiesConfig(); std::wstring targetWorldName = serverProperties.worldName; if (targetWorldName.empty()) { @@ -491,7 +524,12 @@ int main(int argc, char **argv) LogWorldIO("initial save completed"); } } - DWORD nextAutosaveTick = GetTickCount() + kAutosaveIntervalMs; + DWORD autosaveIntervalMs = kDefaultAutosaveIntervalMs; + if (serverProperties.autosaveIntervalSeconds > 0) + { + autosaveIntervalMs = (DWORD)(serverProperties.autosaveIntervalSeconds * 1000); + } + DWORD nextAutosaveTick = GetTickCount() + autosaveIntervalMs; bool autosaveRequested = false; while (!g_shutdownRequested && !app.m_bShutdown) @@ -519,7 +557,7 @@ int main(int argc, char **argv) app.SetXuiServerAction(kServerActionPad, eXuiServerAction_AutoSaveGame); autosaveRequested = true; } - nextAutosaveTick = now + kAutosaveIntervalMs; + nextAutosaveTick = now + autosaveIntervalMs; } Sleep(10);