メインコンテンツまでスキップ

ライブオペレーション

ライブオペレーションは、期間限定イベント、リーダーボード、実績、クラウドセーブ、自動バックアップ、およびModサポートをカバーします。これらのシステムにより、リリース後も継続的なコンテンツ配信とプレイヤーエンゲージメントが可能になります。

LiveOps センター

イベント、リーダーボード、実績をひとつの画面に。進行中のイベントのカウントダウンはクライアントの時計ではなくサーバー時刻なので、プレイヤーがシステムの日付を変えてイベントを早く終わらせることはできません。

アーキテクチャ概要​

クラスファイル責任
EventServicePersistence/PersistenceAndSystems.csシーズン/期間限定イベント管理
LeaderboardServicePersistence/PersistenceAndSystems.csスコア登録機能付きランキング
AchievementServicePersistence/PersistenceAndSystems.cs実績追跡とアンロックシステム
CloudSaveServicePersistence/PersistenceAndSystems.cs競合検出付きクラウドセーブのアップロード/ダウンロード
BackupSchedulerAntiCheat/AntiCheatManager.cs自動定期クラウドバックアップ
ModLoaderPersistence/PersistenceAndSystems.cs実行時のコミュニティMod読み込み

NakamaManager.Instanceからアクセス:

var events = NakamaManager.Instance.Events;
var leaderboards = NakamaManager.Instance.Leaderboards;
var achievements = NakamaManager.Instance.Achievements;
var cloudSave = NakamaManager.Instance.CloudSave;
var mods = NakamaManager.Instance.Mods;

イベントサービス​

EventServiceは期間限定のライブイベント(コミュニティデイ、シーズンコンテンツ、特別な遭遇)を管理します。

アクティブなイベントの取得​

List<LiveEvent> activeEvents = await events.GetActiveEventsAsync();

foreach (var evt in activeEvents)
{
// evt.Id -- 一意のイベントID
// evt.Name -- 表示名
// evt.Description -- イベント詳細
// evt.StartTime -- イベント開始のUnixタイムスタンプ(ms)
// evt.EndTime -- イベント終了のUnixタイムスタンプ(ms)
// evt.RewardData -- JSONエンコードされた報酬設定
}

イベントライフサイクル​

events.OnEventStarted += (LiveEvent evt) =>
{
Debug.Log($"Event started: {evt.Name}");
// イベントバナーを表示、イベント遭遇を有効化など
};

events.OnEventEnded += (string eventId) =>
{
Debug.Log($"Event ended: {eventId}");
// イベントコンテンツを削除、参加報酬を配布
};

LiveEventデータモデル​

フィールド型説明
Idstring一意のイベント識別子
Namestring表示名
Descriptionstringイベント説明テキスト
StartTimelong開始タイムスタンプ(Unix ms)
EndTimelong終了タイムスタンプ(Unix ms)
RewardDatastringJSONエンコードされた報酬設定

イベントはNakamaコンソールを通じてサーバーサイドで設定されます。クライアントはアクティブなイベントをポーリングし、開始/終了通知に反応します。

リーダーボードサービス​

LeaderboardServiceは、スコア登録とランキングクエリを備えたリーダーボードを提供します。

スコアの登録​

await leaderboards.SubmitScoreAsync(
boardId: "pvp_season_1",
score: 1850);

await leaderboards.SubmitScoreAsync(
boardId: "dex_completion",
score: 151);

ランキングの照会​

// 上位プレイヤーを取得
List<LeaderboardEntry> top100 = await leaderboards.GetTopPlayersAsync(
boardId: "pvp_season_1",
limit: 100);

foreach (var entry in top100)
{
// entry.Rank, entry.DisplayName, entry.Score, entry.UserId
}

// 自分のランクを取得
LeaderboardEntry myRank = await leaderboards.GetMyRankAsync("pvp_season_1");

データの更新​

await leaderboards.RefreshAsync();

LeaderboardEntryデータモデル​

フィールド型説明
UserIdstringプレイヤーのNakamaユーザーID
DisplayNamestringプレイヤーの表示名
Scorelongスコア値
Rankintリーダーボード上の順位

リーダーボードはシーズンリセットをサポートしています -- シーズンごとに新しいボードIDを作成し(例:pvp_season_2)、古いものはアーカイブします。

実績サービス​

AchievementServiceは進捗状況を追跡してプレイヤーの功績を管理します。

実績の一覧表示​

List<Achievement> all = await achievements.GetAchievementsAsync();

foreach (var ach in all)
{
// ach.Id, ach.Name, ach.Description
// ach.CurrentProgress, ach.MaxProgress
// ach.IsUnlocked, ach.RewardData
}

実績のアンロック​

// 即時アンロック
await achievements.UnlockAsync("first_capture");

// 進捗ベース(例:「モンスターを100匹捕まえる」)
await achievements.UpdateProgressAsync("centurion_catcher", progress: 47);

実績イベント​

achievements.OnAchievementUnlocked += (Achievement ach) =>
{
Debug.Log($"Achievement unlocked: {ach.Name}!");
// アンロックポップアップを表示、ach.RewardDataから報酬を付与
};

データの更新​

await achievements.RefreshAsync();

Achievementデータモデル​

フィールド型説明
Idstring一意の実績ID
Namestring表示名
Descriptionstring実績の説明
CurrentProgressint現在の進捗値
MaxProgressint完了の目標進捗
IsUnlockedbool実績が完了しているかどうか
RewardDatastringJSONエンコードされた報酬設定

クラウドセーブサービス​

CloudSaveServiceはMCEの既存のJSONベースのセーブシステムとNakamaサーバーストレージを橋渡しし、クロスデバイスプレイを可能にします。

セーブのアップロード​

string saveJson = GetLocalSaveJson(); // セーブのシリアル化
bool success = await cloudSave.UploadSaveAsync(saveJson);

// cloudSave.HasCloudSave -- アップロード成功後にtrue
// cloudSave.LastSyncTimestamp -- 最後の同期のUnixタイムスタンプ

セーブのダウンロード​

string saveJson = await cloudSave.DownloadSaveAsync();
// デシリアライズしてローカルゲーム状態に適用

競合検出​

保存時に、システムはローカルデータとクラウドデータの間の競合を検出できます:

SaveConflictInfo conflict = await cloudSave.CheckSaveConflictAsync(localTimestamp);

if (conflict.HasConflict)
{
// conflict.CloudTimestamp vs conflict.LocalTimestamp
// プレイヤーにどちらのセーブを保持するか選択させるUIを表示
}

特化型同期​

// PCストレージボックスを同期(モンスター保管庫)
await cloudSave.SyncPCStorageAsync(pcStorageJson);

// 進行データを同期(バッジ、ポケモン図鑑、クエスト)
await cloudSave.SyncProgressionAsync(progressionJson);

バックアップスケジューラー​

BackupSchedulerは定期的な自動クラウドバックアップを作成するMonoBehaviourです。

設定​

フィールドデフォルト説明
autoSaveIntervalMinutes5自動バックアップ間の分数
maxBackupSlots10最大バックアップ履歴サイズ(FIFOローテーション)

バックアップの対象​

バックアップは、スケジューラーの SaveDataProvider(Func<string>)が返すものをアップロードします。設定していない場合、スケジューラーは LocalSaveDataProvider を使い、ディスク上にある SavegameManager の最新のセーブを読み込みます。プロバイダー、ディスク上のセーブ、接続のいずれかがない場合、バックアップはスキップされ、OnBackupFailed が発行されます。何もアップロードされず、履歴のエントリも書き込まれません。

手動バックアップ​

backupScheduler.CreateBackupAsync();

バックアップからの復元​

string saveJson = await backupScheduler.RestoreBackupAsync(backupId);

バックアップイベント​

backupScheduler.OnBackupCreated += (BackupEntry entry) =>
{
// entry.Id, entry.Timestamp, entry.Type, entry.SizeBytes
};

backupScheduler.OnBackupFailed += (string reason) =>
{
Debug.LogWarning($"Backup failed: {reason}");
};

バックアップタイプ​

タイプ説明
Auto定期的な自動バックアップ
Manualプレイヤー開始のバックアップ
PreBattleバトル開始前のスナップショット
PreTradeトレード実行前のスナップショット

Modサポート​

ModLoaderはコミュニティ作成のコンテンツパックを実行時に読み込むことを可能にします。これはOnlineConfig.EnableModSupport(デフォルト:false)によって制御されます。

Modの読み込み​

Modサポートが有効な場合、インストール済みのModは接続中に自動的に読み込まれます:

await mods.LoadInstalledModsAsync();

Modのインストールと削除​

bool installed = await mods.InstallModAsync("/path/to/mod.zip");
bool removed = await mods.UninstallModAsync(modId);

読み込まれたModの一覧表示​

IReadOnlyList<ModManifest> loadedMods = mods.LoadedMods;

foreach (var mod in loadedMods)
{
// mod.Id, mod.Name, mod.Author, mod.Version
// mod.Description, mod.IsEnabled
// mod.ContentTypes -- 例:["monsters", "maps", "items", "moves"]
}

Modイベント​

mods.OnModLoaded += (ModManifest manifest) =>
{
Debug.Log($"Mod loaded: {manifest.Name} v{manifest.Version}");
};

mods.OnModError += (string modId, string error) =>
{
Debug.LogError($"Mod error ({modId}): {error}");
};

ModManifestデータモデル​

フィールド型説明
Idstring一意のMod識別子
Namestring表示名
AuthorstringMod作成者
Versionstringセマンティックバージョン
DescriptionstringModの説明
ContentTypesstring[]コンテンツタイプ:"monsters"、"maps"、"items"、"moves"
IsEnabledboolModが現在アクティブかどうか

アンチチートシステム​

アンチチート層はライブオペレーションと並行して動作し、ゲームの整合性を維持します。詳細については、AntiCheat/AntiCheatManager.csの専用アンチチートクラスを参照してください:

  • SpeedValidator: 移動速度を設定可能な最大値(デフォルト:8タイル/秒)と比較してスピードハックを検出します。
  • ActionRateLimiter: 設定可能な最小間隔(デフォルト:0.3秒)でアクションスパムを防止します。
  • InventoryAuditor: クライアント報告のインベントリをサーバースナップショットと比較して、アイテムの重複や不正アイテムを検出します。
  • AntiCheatManager: 違反しきい値で全てのバリデーターを調整 -- 10回の違反でキック、25回でBANをトリガーします。