mirror of
https://github.com/smartcmd/MinecraftConsoles.git
synced 2026-08-20 09:57:09 +00:00
update: converted Japanese comments to English
This commit is contained in:
parent
83063f4b73
commit
35f81c6e4f
|
|
@ -13,11 +13,14 @@ namespace ServerRuntime
|
|||
};
|
||||
|
||||
/**
|
||||
* 文字列をログレベルへ変換する(`debug`/`info`/`warn`/`error`)
|
||||
* **Parse Log Level String**
|
||||
*
|
||||
* @param value 変換元文字列
|
||||
* @param outLevel 変換結果の出力先
|
||||
* @return 変換成功時 `true`
|
||||
* Converts a string value into log level (`debug`/`info`/`warn`/`error`)
|
||||
* ログレベル文字列の変換処理
|
||||
*
|
||||
* @param value Source string
|
||||
* @param outLevel Output location for parsed level
|
||||
* @return `true` when conversion succeeds
|
||||
*/
|
||||
bool TryParseServerLogLevel(const char *value, EServerLogLevel *outLevel);
|
||||
|
||||
|
|
@ -29,7 +32,7 @@ namespace ServerRuntime
|
|||
void LogWarn(const char *category, const char *message);
|
||||
void LogError(const char *category, const char *message);
|
||||
|
||||
/** 指定レベル・カテゴリでフォーマットログを出力する */
|
||||
/** Emit formatted log output with the specified level and category */
|
||||
void LogDebugf(const char *category, const char *format, ...);
|
||||
void LogInfof(const char *category, const char *format, ...);
|
||||
void LogWarnf(const char *category, const char *format, ...);
|
||||
|
|
|
|||
|
|
@ -196,22 +196,24 @@ static std::string LogLevelToPropertyValue(EServerLogLevel level)
|
|||
}
|
||||
|
||||
/**
|
||||
* 任意文字列を保存先IDとして安全な形式に正規化する
|
||||
* **Normalize Save ID**
|
||||
*
|
||||
* 変換ルール:
|
||||
* - 英字は小文字化
|
||||
* - `[a-z0-9_.-]` のみ保持
|
||||
* - 空白/非対応文字は `_` に置換
|
||||
* - 空値は `world` に補正
|
||||
* - 最大長はストレージ制約に合わせて制限
|
||||
* Normalizes an arbitrary string into a safe save destination ID
|
||||
* Conversion rules:
|
||||
* - Lowercase alphabetic characters
|
||||
* - Keep only `[a-z0-9_.-]`
|
||||
* - Replace spaces and unsupported characters with `_`
|
||||
* - Fallback to `world` when empty
|
||||
* - Enforce max length to match storage constraints
|
||||
* 保存先IDの正規化処理
|
||||
*/
|
||||
static std::string NormalizeSaveId(const std::string &source)
|
||||
{
|
||||
std::string out;
|
||||
out.reserve(source.length());
|
||||
|
||||
// Storage 側の保存先IDとして安全に扱える文字セットへ正規化する
|
||||
// 不正文字は '_' に落とし、大小は吸収して衝突を減らす
|
||||
// Normalize into a character set that is safe for storage save IDs
|
||||
// Replace invalid characters with '_' and fold letter case to reduce collisions
|
||||
for (size_t i = 0; i < source.length(); ++i)
|
||||
{
|
||||
unsigned char ch = (unsigned char)source[i];
|
||||
|
|
@ -241,13 +243,13 @@ static std::string NormalizeSaveId(const std::string &source)
|
|||
out = "world";
|
||||
}
|
||||
|
||||
// 先頭文字が扱いづらいケースを避けるため、必要に応じて接頭辞を付与する
|
||||
// Add a prefix when needed to avoid awkward leading characters
|
||||
if (!((out[0] >= 'a' && out[0] <= 'z') || (out[0] >= '0' && out[0] <= '9')))
|
||||
{
|
||||
out = std::string("w_") + out;
|
||||
}
|
||||
|
||||
// 4J 側の filename バッファ制約に合わせて長さを制限する
|
||||
// Clamp length to the 4J-side filename buffer constraint
|
||||
if (out.length() > kMaxSaveIdLength)
|
||||
{
|
||||
out.resize(kMaxSaveIdLength);
|
||||
|
|
@ -271,11 +273,13 @@ static void ApplyDefaultServerProperties(std::unordered_map<std::string, std::st
|
|||
}
|
||||
|
||||
/**
|
||||
* `server.properties` 形式のテキストをパースして key/value を抽出する
|
||||
* **Parse server.properties Text**
|
||||
*
|
||||
* - `#` / `!` 始まりはコメントとして無視
|
||||
* - `=` または `:` を区切りとして解釈
|
||||
* - 不正行はスキップして継続
|
||||
* Extracts key/value pairs from `server.properties` format text
|
||||
* - Ignores lines starting with `#` or `!` as comments
|
||||
* - Accepts `=` or `:` as separators
|
||||
* - Skips invalid lines and continues
|
||||
* server.propertiesのパース処理
|
||||
*/
|
||||
static bool ReadServerPropertiesFile(const char *filePath, std::unordered_map<std::string, std::string> *properties, int *outParsedCount)
|
||||
{
|
||||
|
|
@ -351,9 +355,11 @@ static bool ReadServerPropertiesFile(const char *filePath, std::unordered_map<st
|
|||
}
|
||||
|
||||
/**
|
||||
* key/value を `server.properties` として書き戻す
|
||||
* **Write server.properties Text**
|
||||
*
|
||||
* 出力順を安定化するため、キーをソートして保存する
|
||||
* Writes key/value data back as `server.properties`
|
||||
* Sorts keys before writing to keep output order stable
|
||||
* server.propertiesの書き戻し処理
|
||||
*/
|
||||
static bool WriteServerPropertiesFile(const char *filePath, const std::unordered_map<std::string, std::string> &properties)
|
||||
{
|
||||
|
|
@ -574,12 +580,14 @@ static std::string ReadNormalizedLevelTypeProperty(
|
|||
}
|
||||
|
||||
/**
|
||||
* 実効的なワールド設定を読み込み、欠損/不正を補正して返す
|
||||
* **Load Effective Server Properties Config**
|
||||
*
|
||||
* - ファイルが無い場合はデフォルトで生成
|
||||
* - 必須キー欠損時は補完
|
||||
* - `level-id` を安全形式へ正規化
|
||||
* - 修正が発生した場合は自動で再保存
|
||||
* Loads effective world settings, repairs missing or invalid values, and returns normalized config
|
||||
* - Creates defaults when file is missing
|
||||
* - Fills required keys when absent
|
||||
* - Normalizes `level-id` to a safe format
|
||||
* - Auto-saves when any fix is applied
|
||||
* 実効設定の読み込みと補正処理
|
||||
*/
|
||||
ServerPropertiesConfig LoadServerPropertiesConfig()
|
||||
{
|
||||
|
|
@ -620,7 +628,7 @@ ServerPropertiesConfig LoadServerPropertiesConfig()
|
|||
|
||||
for (std::unordered_map<std::string, std::string>::const_iterator it = loaded.begin(); it != loaded.end(); ++it)
|
||||
{
|
||||
// 既存値をデフォルトへ上書きマージして、未知キーも可能な限り維持する
|
||||
// Merge loaded values over defaults and keep unknown keys whenever possible
|
||||
merged[it->first] = it->second;
|
||||
}
|
||||
|
||||
|
|
@ -634,13 +642,13 @@ ServerPropertiesConfig LoadServerPropertiesConfig()
|
|||
std::string worldSaveId = TrimAscii(merged["level-id"]);
|
||||
if (worldSaveId.empty())
|
||||
{
|
||||
// level-id が未設定なら level-name から自動生成して保存先を固定する
|
||||
// If level-id is missing, derive it from level-name to lock save destination
|
||||
worldSaveId = NormalizeSaveId(worldName);
|
||||
shouldWrite = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 既存の level-id も正規化して、将来の不整合を防ぐ
|
||||
// Normalize existing level-id as well to avoid future inconsistencies
|
||||
std::string normalized = NormalizeSaveId(worldSaveId);
|
||||
if (normalized != worldSaveId)
|
||||
{
|
||||
|
|
@ -713,10 +721,12 @@ ServerPropertiesConfig LoadServerPropertiesConfig()
|
|||
}
|
||||
|
||||
/**
|
||||
* ワールド識別情報を保存しつつ、他設定キーを可能な限り保持する
|
||||
* **Save World Identity While Preserving Other Keys**
|
||||
*
|
||||
* - 既存ファイルを読み取り、未知キーも含めてマージ
|
||||
* - `level-name` / `level-id` のみ更新して書き戻す
|
||||
* Saves world identity fields while preserving as many other settings as possible
|
||||
* - Reads existing file and merges including unknown keys
|
||||
* - Updates only `level-name` and `level-id` before writing back
|
||||
* ワールド識別情報の保存処理
|
||||
*/
|
||||
bool SaveServerPropertiesConfig(const ServerPropertiesConfig &config)
|
||||
{
|
||||
|
|
@ -729,7 +739,7 @@ bool SaveServerPropertiesConfig(const ServerPropertiesConfig &config)
|
|||
{
|
||||
for (std::unordered_map<std::string, std::string>::const_iterator it = loaded.begin(); it != loaded.end(); ++it)
|
||||
{
|
||||
// 呼び出し側が触っていないキーを落とさないように、既存内容を保持する
|
||||
// Keep existing content so keys untouched by caller are not dropped
|
||||
merged[it->first] = it->second;
|
||||
}
|
||||
}
|
||||
|
|
@ -737,7 +747,7 @@ bool SaveServerPropertiesConfig(const ServerPropertiesConfig &config)
|
|||
std::string worldName = TrimAscii(WideToUtf8(config.worldName));
|
||||
if (worldName.empty())
|
||||
{
|
||||
worldName = "world"; // デフォルト名
|
||||
worldName = "world"; // Default world name
|
||||
}
|
||||
|
||||
std::string worldSaveId = TrimAscii(config.worldSaveId);
|
||||
|
|
|
|||
|
|
@ -83,9 +83,10 @@ static BOOL WINAPI ConsoleCtrlHandlerProc(DWORD ctrlType)
|
|||
}
|
||||
|
||||
/**
|
||||
* サーバー停止通知が到達するまで待機する終了用スレッド関数
|
||||
* **Wait For Server Stopped Signal**
|
||||
*
|
||||
* シャットダウン時にネットワーク層の停止完了を同期するために使う
|
||||
* Thread entry used during shutdown to wait until the network layer reports server stop completion
|
||||
* 停止通知待機用の終了スレッド処理
|
||||
*/
|
||||
static int WaitForServerStoppedThreadProc(void *)
|
||||
{
|
||||
|
|
@ -258,10 +259,11 @@ static void ApplyServerPropertiesToDedicatedConfig(const ServerPropertiesConfig
|
|||
}
|
||||
|
||||
/**
|
||||
* 非同期処理進行に必須なコアサブシステムを1フレーム分進める
|
||||
* **Tick Core Async Subsystems**
|
||||
*
|
||||
* ストレージ/プロフィール/ネットワークの進行停止を防ぐため、
|
||||
* 待機ループ中も継続的に呼び出す
|
||||
* Advances core subsystems for one frame to keep async processing alive
|
||||
* Call continuously even inside wait loops to avoid stalling storage/profile/network work
|
||||
* 非同期進行維持のためのティック処理
|
||||
*/
|
||||
static void TickCoreSystems()
|
||||
{
|
||||
|
|
@ -271,7 +273,10 @@ static void TickCoreSystems()
|
|||
}
|
||||
|
||||
/**
|
||||
* キュー済みの XUI / サーバーアクションを1回処理する
|
||||
* **Handle Queued XUI Server Action Once**
|
||||
*
|
||||
* Processes queued XUI/server action once
|
||||
* XUIアクションの単発処理
|
||||
*/
|
||||
static void HandleXuiActions()
|
||||
{
|
||||
|
|
@ -302,7 +307,7 @@ int main(int argc, char **argv)
|
|||
SetConsoleCtrlHandler(ConsoleCtrlHandlerProc, TRUE);
|
||||
SetExeWorkingDirectory();
|
||||
|
||||
// server.properties の値をベース設定として読み込み、CLI で必要に応じて上書きする
|
||||
// Load base settings from server.properties, then override with CLI values when provided
|
||||
ServerPropertiesConfig serverProperties = LoadServerPropertiesConfig();
|
||||
ApplyServerPropertiesToDedicatedConfig(serverProperties, &config);
|
||||
|
||||
|
|
@ -445,12 +450,12 @@ int main(int argc, char **argv)
|
|||
app.SetGameHostOption(eGameHostOption_DoDaylightCycle, serverProperties.doDaylightCycle ? 1 : 0);
|
||||
|
||||
StorageManager.SetSaveDisabled(serverProperties.disableSaving);
|
||||
// server.properties から world 名と固定 save-id を取得し、
|
||||
// WorldManager にロード/新規作成判定を委譲する
|
||||
// Read world name and fixed save-id from server.properties
|
||||
// Delegate load-vs-create decision to WorldManager
|
||||
std::wstring targetWorldName = serverProperties.worldName;
|
||||
if (targetWorldName.empty())
|
||||
{
|
||||
targetWorldName = L"world"; // デフォ名
|
||||
targetWorldName = L"world"; // Default world name
|
||||
}
|
||||
WorldBootstrapResult worldBootstrap = BootstrapWorldForServer(serverProperties, kServerActionPad, &TickCoreSystems);
|
||||
if (worldBootstrap.status == eWorldBootstrap_Loaded)
|
||||
|
|
@ -458,8 +463,8 @@ int main(int argc, char **argv)
|
|||
const std::string &loadedSaveFilename = worldBootstrap.resolvedSaveId;
|
||||
if (!loadedSaveFilename.empty() && _stricmp(loadedSaveFilename.c_str(), serverProperties.worldSaveId.c_str()) != 0)
|
||||
{
|
||||
// 実際に読み込まれた save-id を設定ファイルへ戻して、
|
||||
// 次回起動時の探索キーを揃える
|
||||
// Persist the actually loaded save-id back to config
|
||||
// Keep lookup keys aligned for next startup
|
||||
LogWorldIO("updating level-id to loaded save filename");
|
||||
serverProperties.worldSaveId = loadedSaveFilename;
|
||||
if (!SaveServerPropertiesConfig(serverProperties))
|
||||
|
|
@ -516,8 +521,8 @@ int main(int argc, char **argv)
|
|||
LogInfof("startup", "Dedicated server listening on %s:%d", g_Win64MultiplayerIP, g_Win64MultiplayerPort);
|
||||
if (worldBootstrap.status == eWorldBootstrap_CreatedNew && !g_shutdownRequested && !app.m_bShutdown)
|
||||
{
|
||||
// Windows64 では新規ワールド直後の saveToDisc を抑止しているため
|
||||
// Dedicated Server はここで初回保存を明示的に実行する
|
||||
// Windows64 suppresses saveToDisc right after new world creation
|
||||
// Dedicated Server explicitly runs the initial save here
|
||||
LogWorldIO("requesting initial save for newly created world");
|
||||
WaitForWorldActionIdle(kServerActionPad, 5000, &TickCoreSystems, &HandleXuiActions);
|
||||
app.SetXuiServerAction(kServerActionPad, eXuiServerAction_AutoSaveGame);
|
||||
|
|
@ -582,7 +587,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
|
||||
LogWorldIO("requesting save before shutdown");
|
||||
// 終了時保存の前に Idle へ戻して、既存の action と競合しないようにする
|
||||
// Return to Idle before shutdown save to avoid action conflicts
|
||||
WaitForWorldActionIdle(kServerActionPad, 5000, &TickCoreSystems, &HandleXuiActions);
|
||||
app.SetXuiServerAction(kServerActionPad, eXuiServerAction_SaveGame);
|
||||
if (!WaitForWorldActionIdle(kServerActionPad, 15000, &TickCoreSystems, &HandleXuiActions))
|
||||
|
|
|
|||
|
|
@ -51,12 +51,14 @@ struct SaveDataLoadContext
|
|||
};
|
||||
|
||||
/**
|
||||
* `StorageManager` に保存先ID(`level-id`)を反映する
|
||||
* **Apply Save ID To StorageManager**
|
||||
*
|
||||
* - 起動直後や保存直前に毎回同じIDを設定し、保存先のブレを防ぐ
|
||||
* - 空文字は無効値として無視する
|
||||
* Applies the configured save destination ID (`level-id`) to `StorageManager`
|
||||
* - Re-applies the same ID at startup and before save to avoid destination drift
|
||||
* - Ignores empty values as invalid
|
||||
* 保存先IDの適用処理
|
||||
*
|
||||
* @param saveFilename 正規化済みの保存先ID
|
||||
* @param saveFilename Normalized save destination ID
|
||||
*/
|
||||
static void SetStorageSaveUniqueFilename(const std::string &saveFilename)
|
||||
{
|
||||
|
|
@ -94,9 +96,10 @@ static void LogEnumeratedSaveInfo(int index, const SAVE_INFO &saveInfo)
|
|||
}
|
||||
|
||||
/**
|
||||
* セーブ一覧取得 (callback)
|
||||
* **Save List Callback**
|
||||
*
|
||||
* 非同期結果を `SaveInfoQueryContext` に取り込み、待機側へ完了通知する
|
||||
* Captures async save-list results into `SaveInfoQueryContext` and marks completion for the waiter
|
||||
* セーブ一覧取得の完了通知
|
||||
*/
|
||||
static int GetSavesInfoCallbackProc(LPVOID lpParam, SAVE_DETAILS *pSaveDetails, const bool bRes)
|
||||
{
|
||||
|
|
@ -111,9 +114,10 @@ static int GetSavesInfoCallbackProc(LPVOID lpParam, SAVE_DETAILS *pSaveDetails,
|
|||
}
|
||||
|
||||
/**
|
||||
* セーブデータロード (callback)
|
||||
* **Save Data Load Callback**
|
||||
*
|
||||
* 破損判定などの結果を `SaveDataLoadContext` に反映する
|
||||
* Writes load results such as corruption status into `SaveDataLoadContext`
|
||||
* セーブ読み込み結果の反映
|
||||
*/
|
||||
static int LoadSaveDataCallbackProc(LPVOID lpParam, const bool bIsCorrupt, const bool bIsOwner)
|
||||
{
|
||||
|
|
@ -128,13 +132,14 @@ static int LoadSaveDataCallbackProc(LPVOID lpParam, const bool bIsCorrupt, const
|
|||
}
|
||||
|
||||
/**
|
||||
* セーブ一覧取得の完了を待機する
|
||||
* **Wait For Save List Completion**
|
||||
*
|
||||
* - callback 完了通知を第一候補として待つ
|
||||
* - 実装差異により callback より先に `ReturnSavesInfo()` が埋まるケースもあるため、
|
||||
* ポーリング経路でも救済する
|
||||
* Waits until save-list retrieval completes
|
||||
* - Prefers callback completion as the primary signal
|
||||
* - Also falls back to polling because some environments populate `ReturnSavesInfo()` before callback
|
||||
* セーブ一覧待機の補助処理
|
||||
*
|
||||
* @return 完了を検知できたら `true`
|
||||
* @return `true` when completion is detected
|
||||
*/
|
||||
static bool WaitForSaveInfoResult(SaveInfoQueryContext *context, DWORD timeoutMs, WorldManagerTickProc tickProc)
|
||||
{
|
||||
|
|
@ -148,8 +153,8 @@ static bool WaitForSaveInfoResult(SaveInfoQueryContext *context, DWORD timeoutMs
|
|||
|
||||
if (context->details == NULL)
|
||||
{
|
||||
// 実装/環境によっては callback より先に ReturnSavesInfo が埋まるため、
|
||||
// callback 完了待ちだけに依存せずポーリングでも救済する
|
||||
// Some implementations fill ReturnSavesInfo before the callback
|
||||
// Keep polling as a fallback instead of relying only on callback completion
|
||||
SAVE_DETAILS *details = StorageManager.ReturnSavesInfo();
|
||||
if (details != NULL)
|
||||
{
|
||||
|
|
@ -171,9 +176,12 @@ static bool WaitForSaveInfoResult(SaveInfoQueryContext *context, DWORD timeoutMs
|
|||
}
|
||||
|
||||
/**
|
||||
* セーブ本体ロード完了 callback を待機する
|
||||
* **Wait For Save Data Load Completion**
|
||||
*
|
||||
* @return callback 到達で `true`、タイムアウト時は `false`
|
||||
* Waits for the save-data load callback to complete
|
||||
* セーブ本体の読み込み待機
|
||||
*
|
||||
* @return `true` when callback is reached, `false` on timeout
|
||||
*/
|
||||
static bool WaitForSaveLoadResult(SaveDataLoadContext *context, DWORD timeoutMs, WorldManagerTickProc tickProc)
|
||||
{
|
||||
|
|
@ -196,9 +204,10 @@ static bool WaitForSaveLoadResult(SaveDataLoadContext *context, DWORD timeoutMs,
|
|||
}
|
||||
|
||||
/**
|
||||
* ワールド名ベースで `SAVE_INFO` が一致するか判定する
|
||||
* **Match SAVE_INFO By World Name**
|
||||
*
|
||||
* タイトルと保存先ファイル名の両方を比較対象にする
|
||||
* Compares both save title and save filename against the target world name
|
||||
* ワールド名一致判定
|
||||
*/
|
||||
static bool SaveInfoMatchesWorldName(const SAVE_INFO &saveInfo, const std::wstring &targetWorldName)
|
||||
{
|
||||
|
|
@ -223,7 +232,10 @@ static bool SaveInfoMatchesWorldName(const SAVE_INFO &saveInfo, const std::wstri
|
|||
}
|
||||
|
||||
/**
|
||||
* 保存先ID(`UTF8SaveFilename`)で `SAVE_INFO` が一致するか判定する
|
||||
* **Match SAVE_INFO By Save Filename**
|
||||
*
|
||||
* Checks whether `SAVE_INFO` matches by save destination ID (`UTF8SaveFilename`)
|
||||
* 保存先ID一致判定
|
||||
*/
|
||||
static bool SaveInfoMatchesSaveFilename(const SAVE_INFO &saveInfo, const std::string &targetSaveFilename)
|
||||
{
|
||||
|
|
@ -236,30 +248,34 @@ static bool SaveInfoMatchesSaveFilename(const SAVE_INFO &saveInfo, const std::st
|
|||
}
|
||||
|
||||
/**
|
||||
* ワールド識別情報(`level-name` + `level-id`)をストレージ側へ適用する
|
||||
* **Apply World Identity To Storage**
|
||||
*
|
||||
* - 表示名だけ/IDだけの片設定を避け、両方を常に明示する
|
||||
* - 環境差異で新規保存先が増殖する事象を回避するための防御策
|
||||
* Applies world identity (`level-name` + `level-id`) to storage
|
||||
* - Always sets both display name and ID to avoid partial configuration
|
||||
* - Helps prevent unintended new save destinations across environment differences
|
||||
* 保存先と表示名の同期処理
|
||||
*/
|
||||
static void ApplyWorldStorageTarget(const std::wstring &worldName, const std::string &saveId)
|
||||
{
|
||||
// タイトル(表示名)と保存先ID(実体フォルダ名)を明示的に両方設定する
|
||||
// どちらか片方だけだと環境によって新規保存先が生成されることがある
|
||||
// Set both title (display name) and save ID (actual folder name) explicitly
|
||||
// Setting only one side can create unexpected new save targets in some environments
|
||||
StorageManager.SetSaveTitle(worldName.c_str());
|
||||
SetStorageSaveUniqueFilename(saveId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 対象ワールドに一致するセーブを探索し、見つかれば起動用バイナリを抽出する
|
||||
* **Prepare World Save Data For Startup**
|
||||
*
|
||||
* 一致判定の優先順位:
|
||||
* 1. `level-id`(`UTF8SaveFilename`)の完全一致
|
||||
* 2. フォールバックとして `level-name` とタイトル/ファイル名一致
|
||||
* Searches for a save matching the target world and extracts startup payload when found
|
||||
* Match priority:
|
||||
* 1. Exact match by `level-id` (`UTF8SaveFilename`)
|
||||
* 2. Fallback match by `level-name` against title or filename
|
||||
* ワールド一致セーブの探索処理
|
||||
*
|
||||
* @return
|
||||
* - `eWorldSaveLoad_Loaded`: 既存セーブをロードできた
|
||||
* - `eWorldSaveLoad_NotFound`: 一致セーブなし
|
||||
* - `eWorldSaveLoad_Failed`: API失敗/破損/データ不正
|
||||
* - `eWorldSaveLoad_Loaded`: Existing save loaded successfully
|
||||
* - `eWorldSaveLoad_NotFound`: No matching save found
|
||||
* - `eWorldSaveLoad_Failed`: API failure, corruption, or invalid data
|
||||
*/
|
||||
static EWorldSaveLoadResult PrepareWorldSaveData(
|
||||
const std::wstring &targetWorldName,
|
||||
|
|
@ -315,8 +331,8 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
|||
int matchedIndex = -1;
|
||||
if (!targetSaveFilename.empty())
|
||||
{
|
||||
// 1) 保存先IDが指定されている場合は最優先で一致検索
|
||||
// これが最も安定して「同じワールド」を再利用できる(勝手に上書きで新規作成されることがある)
|
||||
// 1) If save ID is provided, search by it first
|
||||
// This is the most stable way to reuse the same world target
|
||||
for (int i = 0; i < infoContext.details->iSaveC; ++i)
|
||||
{
|
||||
LogEnumeratedSaveInfo(i, infoContext.details->SaveInfoA[i]);
|
||||
|
|
@ -338,8 +354,8 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
|||
|
||||
for (int i = 0; i < infoContext.details->iSaveC; ++i)
|
||||
{
|
||||
// 2) 保存先IDで見つからない場合は互換フォールバックとして
|
||||
// タイトル/ファイル名と worldName の一致を試す
|
||||
// 2) If no save matched by ID, try compatibility fallback
|
||||
// Match worldName against save title or save filename
|
||||
if (matchedIndex >= 0)
|
||||
{
|
||||
break;
|
||||
|
|
@ -375,7 +391,7 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
|||
std::string resolvedSaveFilename;
|
||||
if (matchedSaveInfo->UTF8SaveFilename[0] != 0)
|
||||
{
|
||||
// 実際に見つかった保存先IDを優先採用し、今後の保存も同じ先に固定する
|
||||
// Prefer the save ID that was actually matched, then keep using it for future saves
|
||||
resolvedSaveFilename = matchedSaveInfo->UTF8SaveFilename;
|
||||
SetStorageSaveUniqueFilename(resolvedSaveFilename);
|
||||
}
|
||||
|
|
@ -414,7 +430,7 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
|||
unsigned int saveSize = StorageManager.GetSaveSize();
|
||||
if (saveSize == 0)
|
||||
{
|
||||
// 読み込み成功扱いでも実データが0byteなら安全側で失敗扱いにする
|
||||
// Treat zero-byte payload as failure even when load API reports success
|
||||
LogWorldIO("loaded save has zero size");
|
||||
return eWorldSaveLoad_Failed;
|
||||
}
|
||||
|
|
@ -434,11 +450,13 @@ static EWorldSaveLoadResult PrepareWorldSaveData(
|
|||
}
|
||||
|
||||
/**
|
||||
* サーバー起動時のワールド状態を確定する
|
||||
* **Bootstrap World State For Server Startup**
|
||||
*
|
||||
* - 既存セーブがあればロードして返す
|
||||
* - 見つからなければ新規ワールド文脈を準備して返す
|
||||
* - 失敗時は起動中断判断のため `Failed` を返す
|
||||
* Determines final world startup state
|
||||
* - Returns loaded save data when an existing save is found
|
||||
* - Prepares a new world context when not found
|
||||
* - Returns `Failed` when startup should be aborted
|
||||
* サーバー起動時のワールド確定処理
|
||||
*/
|
||||
WorldBootstrapResult BootstrapWorldForServer(
|
||||
const ServerPropertiesConfig &config,
|
||||
|
|
@ -478,8 +496,8 @@ WorldBootstrapResult BootstrapWorldForServer(
|
|||
}
|
||||
else if (worldLoadResult == eWorldSaveLoad_NotFound)
|
||||
{
|
||||
// 一致セーブがない場合のみ新規コンテキストを作る
|
||||
// この時点で saveId を固定しておくことで、次回起動時に同じ場所へ保存される
|
||||
// Create a new context only when no matching save exists
|
||||
// Fix saveId here so the next startup writes to the same location
|
||||
result.status = eWorldBootstrap_CreatedNew;
|
||||
result.resolvedSaveId = targetSaveFilename;
|
||||
LogStartupStep("configured world not found; creating new world");
|
||||
|
|
@ -496,9 +514,10 @@ WorldBootstrapResult BootstrapWorldForServer(
|
|||
}
|
||||
|
||||
/**
|
||||
* サーバー側 XUI アクションが `Idle` に戻るまで待機する
|
||||
* **Wait Until Server XUI Action Is Idle**
|
||||
*
|
||||
* 保存アクション中も tick/handle を継続し、非同期処理の進行停止を防ぐ
|
||||
* Keeps tick/handle running during save action so async processing does not stall
|
||||
* XUIアクション待機中の進行維持処理
|
||||
*/
|
||||
bool WaitForWorldActionIdle(
|
||||
int actionPad,
|
||||
|
|
@ -509,8 +528,8 @@ bool WaitForWorldActionIdle(
|
|||
DWORD start = GetTickCount();
|
||||
while (app.GetXuiServerAction(actionPad) != eXuiServerAction_Idle && !MinecraftServer::serverHalted())
|
||||
{
|
||||
// 待機中もネットワーク/ストレージ進行を止めない
|
||||
// ここを止めると save action 自体が進まずタイムアウトしやすい
|
||||
// Keep network and storage progressing while waiting
|
||||
// If this stops, save action itself may stall and time out
|
||||
if (tickProc != NULL)
|
||||
{
|
||||
tickProc();
|
||||
|
|
|
|||
|
|
@ -10,34 +10,40 @@ typedef struct _LoadSaveDataThreadParam LoadSaveDataThreadParam;
|
|||
|
||||
namespace ServerRuntime
|
||||
{
|
||||
/** 非同期ストレージ/ネットワーク待機中に回すティック関数 */
|
||||
/** Tick callback used while waiting on async storage/network work */
|
||||
typedef void (*WorldManagerTickProc)();
|
||||
/** サーバーアクション待機中に任意で回すアクション処理関数 */
|
||||
/** Optional action handler used while waiting for server actions */
|
||||
typedef void (*WorldManagerHandleActionsProc)();
|
||||
|
||||
/**
|
||||
* ワールド起動準備(既存ロード/新規作成)の結果種別
|
||||
* **World Bootstrap Status**
|
||||
*
|
||||
* Result type for world startup preparation, either loading an existing world or creating a new one
|
||||
* ワールド起動準備の結果種別
|
||||
*/
|
||||
enum EWorldBootstrapStatus
|
||||
{
|
||||
/** 既存ワールドを発見し、ロードできた */
|
||||
/** Found and loaded an existing world */
|
||||
eWorldBootstrap_Loaded,
|
||||
/** 一致するセーブが無く、新規ワールド文脈を作成した */
|
||||
/** No matching save was found, created a new world context */
|
||||
eWorldBootstrap_CreatedNew,
|
||||
/** 起動準備に失敗し、サーバー起動を中断すべき状態 */
|
||||
/** Bootstrap failed and server startup should be aborted */
|
||||
eWorldBootstrap_Failed
|
||||
};
|
||||
|
||||
/**
|
||||
* **World Bootstrap Result**
|
||||
*
|
||||
* Output payload returned by world startup preparation
|
||||
* ワールド起動準備の出力データ
|
||||
*/
|
||||
struct WorldBootstrapResult
|
||||
{
|
||||
/** 起動準備ステータス */
|
||||
/** Bootstrap status */
|
||||
EWorldBootstrapStatus status;
|
||||
/** サーバー初期化用のセーブデータ(新規時は `NULL`) */
|
||||
/** Save data used for server initialization, `NULL` when creating a new world */
|
||||
LoadSaveDataThreadParam *saveData;
|
||||
/** 実際に採用された保存先ID */
|
||||
/** Save ID that was actually selected */
|
||||
std::string resolvedSaveId;
|
||||
|
||||
WorldBootstrapResult()
|
||||
|
|
@ -48,16 +54,18 @@ namespace ServerRuntime
|
|||
};
|
||||
|
||||
/**
|
||||
* サーバー起動用に、対象ワールドのロード/新規作成を確定する
|
||||
* **Bootstrap Target World For Server Startup**
|
||||
*
|
||||
* - `server.properties` の `level-name` / `level-id` を適用
|
||||
* - 既存セーブが見つかればロード
|
||||
* - 見つからない場合のみ新規ワールドとして起動文脈を作成
|
||||
* Resolves whether the target world should be loaded from an existing save or created as new
|
||||
* - Applies `level-name` and `level-id` from `server.properties`
|
||||
* - Loads when a matching save exists
|
||||
* - Creates a new world context only when no save matches
|
||||
* サーバー起動時のロードか新規作成かを確定する
|
||||
*
|
||||
* @param config 正規化済みの `server.properties`
|
||||
* @param actionPad ストレージ非同期APIで使うpadId
|
||||
* @param tickProc 非同期完了待ち中に回すティック関数
|
||||
* @return セーブデータ有無を含む起動準備結果
|
||||
* @param config Normalized `server.properties` values
|
||||
* @param actionPad padId used by async storage APIs
|
||||
* @param tickProc Tick callback run while waiting for async completion
|
||||
* @return Bootstrap result including whether save data was loaded
|
||||
*/
|
||||
WorldBootstrapResult BootstrapWorldForServer(
|
||||
const ServerPropertiesConfig &config,
|
||||
|
|
@ -65,13 +73,16 @@ namespace ServerRuntime
|
|||
WorldManagerTickProc tickProc);
|
||||
|
||||
/**
|
||||
* サーバーアクション状態が `Idle` へ戻るまで待機する
|
||||
* **Wait Until Server Action Returns To Idle**
|
||||
*
|
||||
* @param actionPad 監視対象のpadId
|
||||
* @param timeoutMs タイムアウト時間(ミリ秒)
|
||||
* @param tickProc 待機ループ中に回すティック関数
|
||||
* @param handleActionsProc 任意のアクション処理関数
|
||||
* @return タイムアウト前に `Idle` 到達で `true`
|
||||
* Waits until server action state reaches `Idle`
|
||||
* サーバーアクションの待機処理
|
||||
*
|
||||
* @param actionPad padId to monitor
|
||||
* @param timeoutMs Timeout in milliseconds
|
||||
* @param tickProc Tick callback run inside the wait loop
|
||||
* @param handleActionsProc Optional action handler callback
|
||||
* @return `true` when `Idle` is reached before timeout
|
||||
*/
|
||||
bool WaitForWorldActionIdle(
|
||||
int actionPad,
|
||||
|
|
|
|||
Loading…
Reference in a new issue