# GFramework.Game > 游戏特定功能抽象 - 为游戏开发提供专门的工具和系统 GFramework.Game 是 GFramework 框架的游戏特定功能模块,提供了游戏开发中常用的抽象和工具,包括资产管理、存储系统、序列化等核心功能。 ## 📋 目录 - [概述](#概述) - [核心特性](#核心特性) - [架构模块系统](#架构模块系统) - [资产管理](#资产管理) - [存储系统](#存储系统) - [序列化系统](#序列化系统) - [使用示例](#使用示例) - [最佳实践](#最佳实践) - [性能特性](#性能特性) ## 概述 GFramework.Game 为游戏开发提供了专门的功能模块,与 GFramework.Core 的平台无关特性完美结合,为游戏项目提供了一整套完整的解决方案。 ### 核心设计理念 - **游戏导向**:专门针对游戏开发场景设计 - **模块化架构**:可插拔的模块系统,按需组合 - **数据持久化**:完善的存档和数据管理方案 - **资源管理**:高效的资源加载和管理机制 ## 核心特性 ### 🏗️ 模块化架构 - **AbstractModule**:可重用的架构模块基类 - **生命周期管理**:与框架生命周期深度集成 - **依赖注入**:模块间的依赖自动管理 - **配置驱动**:灵活的模块配置系统 ### 📦 资产管理 - **统一资源目录**:集中化的资源注册和查询 - **类型安全**:编译时类型检查和泛型支持 - **重复检测**:自动检测资源重复注册 - **映射支持**:灵活的资源映射和别名系统 ### 💾 存储系统 - **分层存储**:命名空间支持的存储隔离 - **多格式支持**:JSON、二进制等多种存储格式 - **异步操作**:完整的异步存储 API - **版本兼容**:存档版本管理和迁移支持 ### 🔄 序列化系统 - **JSON 集成**:基于 Newtonsoft.Json 的序列化 - **自定义序列化**:支持自定义序列化逻辑 - **性能优化**:序列化缓存和优化策略 - **类型安全**:强类型的序列化和反序列化 ## 架构模块系统 ### AbstractModule 基础使用 ```csharp using GFramework.Game.architecture; public class AudioModule : AbstractModule { public override void Install(IArchitecture architecture) { // 注册音频相关系统 architecture.RegisterSystem(new AudioSystem()); architecture.RegisterSystem(new MusicSystem()); // 注册音频工具 architecture.RegisterUtility(new AudioUtility()); architecture.RegisterUtility(new MusicUtility()); } public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture) { switch (phase) { case ArchitecturePhase.BeforeModelInit: // 在模型初始化前准备音频资源 PreloadAudioResources(); break; case ArchitecturePhase.Ready: // 架构准备就绪,开始播放背景音乐 StartBackgroundMusic(); break; case ArchitecturePhase.Destroying: // 清理音频资源 CleanupAudioResources(); break; } } private void PreloadAudioResources() { // 预加载音频资源 var audioUtility = architecture.GetUtility(); audioUtility.PreloadAudio("background_music"); audioUtility.PreloadAudio("shoot_sound"); audioUtility.PreloadAudio("explosion_sound"); } private void StartBackgroundMusic() { var musicSystem = architecture.GetSystem(); musicSystem.PlayBackgroundMusic("background_music"); } private void CleanupAudioResources() { var audioUtility = architecture.GetUtility(); audioUtility.UnloadAllAudio(); } } ``` ### 复杂模块示例 ```csharp public class SaveModule : AbstractModule { private ISaveSystem _saveSystem; private IDataMigrationManager _migrationManager; public override void Install(IArchitecture architecture) { // 注册存储相关组件 _saveSystem = new SaveSystem(); architecture.RegisterUtility(_saveSystem); _migrationManager = new DataMigrationManager(); architecture.RegisterUtility(_migrationManager); // 注册数据版本管理 architecture.RegisterSystem(new SaveDataVersionSystem()); } public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture) { switch (phase) { case ArchitecturePhase.AfterModelInit: // 在模型初始化后设置数据迁移 SetupDataMigrations(); break; case ArchitecturePhase.Ready: // 尝试自动加载存档 TryAutoLoadSave(); break; } } private void SetupDataMigrations() { // 设置数据版本迁移 _migrationManager.RegisterMigration(1, 2, MigratePlayerDataV1ToV2); _migrationManager.RegisterMigration(2, 3, MigratePlayerDataV2ToV3); } private void TryAutoLoadSave() { if (_saveSystem.HasAutoSave()) { _saveSystem.LoadAutoSave(); } } private PlayerData MigratePlayerDataV1ToV2(PlayerData v1Data) { return new PlayerData { // 迁移逻辑 Name = v1Data.Name, Health = v1Data.Health, // 新增字段 MaxHealth = 100, Level = 1 }; } private PlayerData MigratePlayerDataV2ToV3(PlayerData v2Data) { return new PlayerData { // 迁移逻辑 Name = v2Data.Name, Health = v2Data.Health, MaxHealth = v2Data.MaxHealth, Level = v2Data.Level, // 新增字段 Experience = 0, Skills = new List() }; } } ``` ### 模块配置 ```csharp public class ModuleConfig { public string SaveDirectory { get; set; } = "saves"; public int AutoSaveInterval { get; set; } = 300; // 5分钟 public bool EnableDataCompression { get; set; } = true; public int MaxSaveSlots { get; set; } = 10; } public class ConfigurableSaveModule : AbstractModule { private ModuleConfig _config; public ConfigurableSaveModule(ModuleConfig config) { _config = config; } public override void Install(IArchitecture architecture) { var saveSystem = new SaveSystem(_config); architecture.RegisterUtility(saveSystem); // 配置自动保存 if (_config.AutoSaveInterval > 0) { architecture.RegisterSystem(new AutoSaveSystem(_config.AutoSaveInterval)); } } } ``` ## 资产管理 ### AbstractAssetCatalogUtility 基础使用 ```csharp using GFramework.Game.assets; public class GameAssetCatalog : AbstractAssetCatalogUtility { public override void Initialize() { base.Initialize(); // 注册场景资产 RegisterSceneUnit("Player", "res://scenes/Player.tscn"); RegisterSceneUnit("Enemy", "res://scenes/Enemy.tscn"); RegisterSceneUnit("Bullet", "res://scenes/Bullet.tscn"); // 注册场景页面 RegisterScenePage("MainMenu", "res://ui/MainMenu.tscn"); RegisterScenePage("GameUI", "res://ui/GameUI.tscn"); RegisterScenePage("PauseMenu", "res://ui/PauseMenu.tscn"); // 注册通用资产 RegisterAsset("PlayerTexture", "res://textures/player.png"); RegisterAsset("EnemyTexture", "res://textures/enemy.png"); RegisterAsset("ShootSound", "res://audio/shoot.wav"); RegisterAsset("ExplosionSound", "res://audio/explosion.wav"); } // 自定义资产验证 protected override bool ValidateAsset(string key, string path) { if (!FileAccess.FileExists(path)) { GD.PrintErr($"Asset file not found: {path}"); return false; } return true; } // 资产加载完成回调 protected override void OnAssetLoaded(string key, object asset) { GD.Print($"Asset loaded: {key}"); // 对特定资产进行额外处理 if (key == "PlayerTexture") { var texture = (Texture2D)asset; // 预处理纹理... } } } ``` ### 资产映射系统 ```csharp public class AssetMapping { public string Key { get; set; } public string Path { get; set; } public Type Type { get; set; } public Dictionary Metadata { get; set; } = new(); } public class AdvancedAssetCatalog : AbstractAssetCatalogUtility { public override void Initialize() { base.Initialize(); // 使用映射对象注册资产 RegisterAsset(new AssetMapping { Key = "Player", Path = "res://scenes/Player.tscn", Type = typeof(PackedScene), Metadata = new Dictionary { ["category"] = "character", ["tags"] = new[] { "player", "hero", "controlled" }, ["health"] = 100, ["speed"] = 5.0f } }); // 批量注册 RegisterAssetsFromDirectory("res://textures/", "*.png", "texture"); RegisterAssetsFromDirectory("res://audio/", "*.wav", "sound"); } private void RegisterAssetsFromDirectory(string directory, string pattern, string prefix) { var dir = DirAccess.Open(directory); if (dir == null) return; dir.ListDirBegin(); var fileName = dir.GetNext(); while (!string.IsNullOrEmpty(fileName)) { if (fileName.EndsWith(pattern.Substring(1))) { var key = $"{prefix}{Path.GetFileNameWithoutExtension(fileName)}"; var path = Path.Combine(directory, fileName); RegisterAsset(key, path); } fileName = dir.GetNext(); } dir.ListDirEnd(); } } ``` ### 资产工厂模式 ```csharp public interface IAssetFactory { T Create(string key); bool CanCreate(string key); } public class PlayerFactory : IAssetFactory { private readonly AbstractAssetCatalogUtility _catalog; public PlayerFactory(AbstractAssetCatalogUtility catalog) { _catalog = catalog; } public Player Create(string key) { var scene = _catalog.GetScene(key); var player = scene.Instantiate(); // 配置玩家 player.Health = GetPlayerHealth(key); player.Speed = GetPlayerSpeed(key); return player; } public bool CanCreate(string key) { return _catalog.HasScene(key) && key.StartsWith("Player"); } private int GetPlayerHealth(string key) { var metadata = _catalog.GetAssetMetadata(key); return metadata?.GetValueOrDefault("health", 100) ?? 100; } private float GetPlayerSpeed(string key) { var metadata = _catalog.GetAssetMetadata(key); return metadata?.GetValueOrDefault("speed", 5.0f) ?? 5.0f; } } ``` ## 存储系统 ### ScopedStorage 分层存储 ```csharp using GFramework.Game.storage; public class GameDataManager { private readonly IStorage _rootStorage; private readonly IStorage _playerStorage; private readonly IStorage _saveStorage; public GameDataManager(IStorage rootStorage) { _rootStorage = rootStorage; // 创建分层存储 _playerStorage = new ScopedStorage(rootStorage, "player"); _saveStorage = new ScopedStorage(rootStorage, "saves"); } public void SavePlayerData(string playerId, PlayerData data) { _playerStorage.Write($"{playerId}/profile", data); _playerStorage.Write($"{playerId}/inventory", data.Inventory); _playerStorage.Write($"{playerId}/stats", data.Stats); } public PlayerData LoadPlayerData(string playerId) { var profile = _playerStorage.Read($"{playerId}/profile"); var inventory = _playerStorage.Read($"{playerId}/inventory", new Inventory()); var stats = _playerStorage.Read($"{playerId}/stats", new PlayerStats()); return new PlayerData { Profile = profile, Inventory = inventory, Stats = stats }; } public void SaveGame(int slotId, SaveData data) { _saveStorage.Write($"slot_{slotId}", data); _saveStorage.Write($"slot_{slotId}/timestamp", DateTime.Now); _saveStorage.Write($"slot_{slotId}/version", data.Version); } public SaveData LoadGame(int slotId) { return _saveStorage.Read($"slot_{slotId}"); } public List GetSaveSlotInfos() { var infos = new List(); for (int i = 1; i <= 10; i++) { var timestamp = _saveStorage.Read($"slot_{i}/timestamp"); var version = _saveStorage.Read($"slot_{i}/version"); if (timestamp != default) { infos.Add(new SaveSlotInfo { SlotId = i, Timestamp = timestamp, Version = version }); } } return infos; } } ``` ### 自定义存储实现 ```csharp public class EncryptedStorage : IStorage { private readonly IStorage _innerStorage; private readonly IEncryptor _encryptor; public EncryptedStorage(IStorage innerStorage, IEncryptor encryptor) { _innerStorage = innerStorage; _encryptor = encryptor; } public void Write(string key, T data) { var json = JsonConvert.SerializeObject(data); var encrypted = _encryptor.Encrypt(json); _innerStorage.Write(key, encrypted); } public T Read(string key, T defaultValue = default) { var encrypted = _innerStorage.Read(key); if (string.IsNullOrEmpty(encrypted)) return defaultValue; var json = _encryptor.Decrypt(encrypted); return JsonConvert.DeserializeObject(json); } public async Task WriteAsync(string key, T data) { var json = JsonConvert.SerializeObject(data); var encrypted = _encryptor.Encrypt(json); await _innerStorage.WriteAsync(key, encrypted); } public async Task ReadAsync(string key, T defaultValue = default) { var encrypted = await _innerStorage.ReadAsync(key); if (string.IsNullOrEmpty(encrypted)) return defaultValue; var json = _encryptor.Decrypt(encrypted); return JsonConvert.DeserializeObject(json); } public bool Has(string key) { return _innerStorage.Has(key); } public void Delete(string key) { _innerStorage.Delete(key); } public void Clear() { _innerStorage.Clear(); } } ``` ### 存储缓存层 ```csharp public class CachedStorage : IStorage { private readonly IStorage _innerStorage; private readonly Dictionary _cache; private readonly Dictionary _cacheTimestamps; private readonly TimeSpan _cacheExpiry; public CachedStorage(IStorage innerStorage, TimeSpan cacheExpiry = default) { _innerStorage = innerStorage; _cacheExpiry = cacheExpiry == default ? TimeSpan.FromMinutes(5) : cacheExpiry; _cache = new Dictionary(); _cacheTimestamps = new Dictionary(); } public T Read(string key, T defaultValue = default) { if (_cache.TryGetValue(key, out var cachedValue) && !IsCacheExpired(key)) { return (T)cachedValue; } var value = _innerStorage.Read(key, defaultValue); UpdateCache(key, value); return value; } public void Write(string key, T data) { _innerStorage.Write(key, data); UpdateCache(key, data); } public async Task ReadAsync(string key, T defaultValue = default) { if (_cache.TryGetValue(key, out var cachedValue) && !IsCacheExpired(key)) { return (T)cachedValue; } var value = await _innerStorage.ReadAsync(key, defaultValue); UpdateCache(key, value); return value; } public async Task WriteAsync(string key, T data) { await _innerStorage.WriteAsync(key, data); UpdateCache(key, data); } public bool Has(string key) { return _cache.ContainsKey(key) || _innerStorage.Has(key); } public void Delete(string key) { _cache.Remove(key); _cacheTimestamps.Remove(key); _innerStorage.Delete(key); } public void Clear() { _cache.Clear(); _cacheTimestamps.Clear(); _innerStorage.Clear(); } public void ClearCache() { _cache.Clear(); _cacheTimestamps.Clear(); } private bool IsCacheExpired(string key) { if (!_cacheTimestamps.TryGetValue(key, out var timestamp)) return true; return DateTime.Now - timestamp > _cacheExpiry; } private void UpdateCache(string key, T value) { _cache[key] = value; _cacheTimestamps[key] = DateTime.Now; } } ``` ## 序列化系统 ### JsonSerializer 使用 ```csharp using GFramework.Game.serializer; public class GameDataSerializer { private readonly JsonSerializer _serializer; public GameDataSerializer() { _serializer = new JsonSerializer(new JsonSerializerSettings { Formatting = Formatting.Indented, NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Populate, TypeNameHandling = TypeNameHandling.Auto }); // 自定义转换器 _serializer.Converters.Add(new Vector2JsonConverter()); _serializer.Converters.Add(new ColorJsonConverter()); _serializer.Converters.Add(new GodotResourceJsonConverter()); } public string Serialize(T data) { return _serializer.Serialize(data); } public T Deserialize(string json) { return _serializer.Deserialize(json); } public void SerializeToFile(string path, T data) { var json = Serialize(data); FileAccess.Open(path, FileAccess.ModeFlags.Write).StoreString(json); } public T DeserializeFromFile(string path) { if (!FileAccess.FileExists(path)) return default(T); var file = FileAccess.Open(path, FileAccess.ModeFlags.Read); var json = file.GetAsText(); file.Close(); return Deserialize(json); } } ``` ### 自定义 JSON 转换器 ```csharp public class Vector2JsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, Vector2 value, JsonSerializer serializer) { writer.WriteStartObject(); writer.WritePropertyName("x"); writer.WriteValue(value.X); writer.WritePropertyName("y"); writer.WriteValue(value.Y); writer.WriteEndObject(); } public override Vector2 ReadJson(JsonReader reader, Type objectType, Vector2 existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return Vector2.Zero; var obj = serializer.Deserialize>(reader); return new Vector2(obj["x"], obj["y"]); } } public class ColorJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, Color value, JsonSerializer serializer) { writer.WriteValue(value.ToHtml()); } public override Color ReadJson(JsonReader reader, Type objectType, Color existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return Colors.White; var html = reader.Value.ToString(); return Color.FromHtml(html); } } public class GodotResourceJsonConverter : JsonConverter { public override void WriteJson(JsonWriter writer, Resource value, JsonSerializer serializer) { if (value == null) { writer.WriteNull(); return; } writer.WriteStartObject(); writer.WritePropertyName("$type"); writer.WriteValue(value.GetType().Name); writer.WritePropertyName("path"); writer.WriteValue(value.ResourcePath); writer.WriteEndObject(); } public override Resource ReadJson(JsonReader reader, Type objectType, Resource existingValue, bool hasExistingValue, JsonSerializer serializer) { if (reader.TokenType == JsonToken.Null) return null; var obj = serializer.Deserialize>(reader); var path = obj["path"]; return GD.Load(path); } } ``` ### 版本化序列化 ```csharp public class VersionedData { public int Version { get; set; } public Dictionary Data { get; set; } = new(); } public class VersionedSerializer { private readonly Dictionary _typeVersions = new(); private readonly Dictionary _migrations = new(); public void RegisterVersion(int version) { _typeVersions[typeof(T)] = version; } public void RegisterMigration(int fromVersion, int toVersion, IDataMigration migration) { var key = GetMigrationKey(typeof(T), fromVersion, toVersion); _migrations[key] = migration; } public string Serialize(T data) { var versioned = new VersionedData { Version = _typeVersions.GetValueOrDefault(typeof(T), 1), Data = new Dictionary { ["type"] = typeof(T).Name, ["data"] = JsonConvert.SerializeObject(data) } }; return JsonConvert.SerializeObject(versioned); } public T Deserialize(string json) { var versioned = JsonConvert.DeserializeObject(json); var currentVersion = _typeVersions.GetValueOrDefault(typeof(T), 1); // 迁移数据到当前版本 var dataJson = MigrateData(versioned.Data["data"] as string, versioned.Version, currentVersion); return JsonConvert.DeserializeObject(dataJson); } private string MigrateData(string dataJson, int fromVersion, int toVersion) { var currentData = dataJson; var currentVersion = fromVersion; while (currentVersion < toVersion) { var migrationKey = GetMigrationKey(typeof(T), currentVersion, currentVersion + 1); if (_migrations.TryGetValue(migrationKey, out var migration)) { currentData = migration.Migrate(currentData); currentVersion++; } else { throw new InvalidOperationException($"No migration found from version {currentVersion} to {currentVersion + 1}"); } } return currentData; } private int GetMigrationKey(Type type, int fromVersion, int toVersion) { return HashCode.Combine(type.Name, fromVersion, toVersion); } } public interface IDataMigration { string Migrate(string data); } public interface IDataMigration : IDataMigration { T Migrate(T data); } ``` ## 使用示例 ### 完整的游戏数据管理系统 ```csharp // 1. 定义数据模型 public class GameProfile { public string PlayerName { get; set; } public DateTime LastPlayed { get; set; } public int TotalPlayTime { get; set; } public List UnlockedAchievements { get; set; } = new(); } public class GameSettings { public float MasterVolume { get; set; } = 1.0f; public float MusicVolume { get; set; } = 0.8f; public float SFXVolume { get; set; } = 0.9f; public GraphicsSettings Graphics { get; set; } = new(); public InputSettings Input { get; set; } = new(); } // 2. 创建游戏管理器 [ContextAware] [Log] public partial class GameManager : Node, IController { private GameAssetCatalog _assetCatalog; private GameDataManager _dataManager; private GameDataSerializer _serializer; protected override void OnInit() { // 初始化资产目录 _assetCatalog = new GameAssetCatalog(); _assetCatalog.Initialize(); // 初始化存储系统 var rootStorage = new FileStorage("user://data/"); var cachedStorage = new CachedStorage(rootStorage); _dataManager = new GameDataManager(cachedStorage); // 初始化序列化器 _serializer = new GameDataSerializer(); Logger.Info("Game manager initialized"); } public void StartNewGame(string playerName) { Logger.Info($"Starting new game for player: {playerName}"); // 创建新的游戏档案 var profile = new GameProfile { PlayerName = playerName, LastPlayed = DateTime.Now, TotalPlayTime = 0 }; _dataManager.SavePlayerData("current", profile); // 加载初始场景 LoadInitialScene(); Context.SendEvent(new NewGameStartedEvent { PlayerName = playerName }); } public void LoadGame(int slotId) { Logger.Info($"Loading game from slot {slotId}"); try { var saveData = _dataManager.LoadGame(slotId); if (saveData != null) { // 恢复游戏状态 RestoreGameState(saveData); Context.SendEvent(new GameLoadedEvent { SlotId = slotId }); Logger.Info("Game loaded successfully"); } else { Logger.Warning($"No save data found in slot {slotId}"); Context.SendEvent(new GameLoadFailedEvent { SlotId = slotId }); } } catch (Exception ex) { Logger.Error($"Failed to load game: {ex.Message}"); Context.SendEvent(new GameLoadFailedEvent { SlotId = slotId, Error = ex.Message }); } } public void SaveGame(int slotId) { Logger.Info($"Saving game to slot {slotId}"); try { var saveData = CreateSaveData(); _dataManager.SaveGame(slotId, saveData); Context.SendEvent(new GameSavedEvent { SlotId = slotId }); Logger.Info("Game saved successfully"); } catch (Exception ex) { Logger.Error($"Failed to save game: {ex.Message}"); Context.SendEvent(new GameSaveFailedEvent { SlotId = slotId, Error = ex.Message }); } } private void LoadInitialScene() { var playerScene = _assetCatalog.GetScene("Player"); var player = playerScene.Instantiate(); var gameWorldScene = _assetCatalog.GetScene("GameWorld"); var gameWorld = gameWorldScene.Instantiate(); AddChild(gameWorld); gameWorld.AddChild(player); } private void RestoreGameState(SaveData saveData) { // 恢复玩家位置 var playerScene = _assetCatalog.GetScene("Player"); var player = playerScene.Instantiate(); player.Position = saveData.PlayerPosition; // 恢复游戏世界 var gameWorldScene = _assetCatalog.GetScene("GameWorld"); var gameWorld = gameWorldScene.Instantiate(); AddChild(gameWorld); gameWorld.AddChild(player); // 恢复其他游戏状态 Context.GetModel().Health.Value = saveData.PlayerHealth; Context.GetModel().CurrentLevel.Value = saveData.CurrentLevel; Context.GetModel().LoadFromData(saveData.Inventory); } private SaveData CreateSaveData() { var player = GetTree().CurrentScene.FindChild("Player"); return new SaveData { PlayerPosition = player?.Position ?? Vector2.Zero, PlayerHealth = Context.GetModel().Health.Value, CurrentLevel = Context.GetModel().CurrentLevel.Value, Inventory = Context.GetModel().GetData(), Timestamp = DateTime.Now, Version = 1 }; } } ``` ### 自动保存系统 ```csharp public class AutoSaveSystem : AbstractSystem { private Timer _autoSaveTimer; private int _currentSaveSlot; private float _autoSaveInterval; public AutoSaveSystem(float intervalMinutes = 5.0f) { _autoSaveInterval = intervalMinutes * 60.0f; } protected override void OnInit() { _autoSaveTimer = new Timer(); _autoSaveTimer.WaitTime = _autoSaveInterval; _autoSaveTimer.Timeout += OnAutoSave; _autoSaveTimer.Autostart = true; AddChild(_autoSaveTimer); // 监听重要事件,立即自动保存 this.RegisterEvent(OnImportantEvent); this.RegisterEvent(OnImportantEvent); this.RegisterEvent(OnImportantEvent); Logger.Info("Auto-save system initialized"); } protected override void OnDestroy() { _autoSaveTimer?.Stop(); // 最后一次自动保存 PerformAutoSave(); } private void OnAutoSave() { PerformAutoSave(); Logger.Debug("Periodic auto-save completed"); } private void OnImportantEvent(IEvent e) { Logger.Info($"Important event {e.GetType().Name}, triggering auto-save"); PerformAutoSave(); } private void PerformAutoSave() { try { var saveData = CreateAutoSaveData(); // 保存到自动存档槽 var storage = Context.GetUtility(); storage.Write("autosave", saveData); storage.Write("autosave/timestamp", DateTime.Now); Logger.Debug("Auto-save completed successfully"); } catch (Exception ex) { Logger.Error($"Auto-save failed: {ex.Message}"); } } private SaveData CreateAutoSaveData() { return new SaveData { // ... 创建保存数据 }; } } ``` ## 最佳实践 ### 🏗️ 数据模型设计 #### 1. 版本化数据结构 ```csharp // 好的做法:版本化数据模型 [Serializable] public class PlayerDataV2 { public int Version { get; set; } = 2; public string Name { get; set; } public int Health { get; set; } public int MaxHealth { get; set; } = 100; // V2 新增 public List Skills { get; set; } = new(); // V2 新增 } // 避免:没有版本控制 [Serializable] public class PlayerData { public string Name { get; set; } public int Health { get; set; } // 未来新增字段会导致兼容性问题 } ``` #### 2. 数据验证 ```csharp public class PlayerData { private string _name; public string Name { get => _name; set { if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Player name cannot be empty"); _name = value; } } public int Health { get => _health; set => _health = Math.Max(0, value); // 确保不为负数 } public void Validate() { if (string.IsNullOrWhiteSpace(Name)) throw new ValidationException("Player name is required"); if (Health < 0) throw new ValidationException("Health cannot be negative"); } } ``` ### 💾 存储策略 #### 1. 分层存储命名 ```csharp // 好的做法:有意义的分层结构 var playerStorage = new ScopedStorage(rootStorage, "players"); var saveStorage = new ScopedStorage(rootStorage, "saves"); var settingsStorage = new ScopedStorage(rootStorage, "settings"); var tempStorage = new ScopedStorage(rootStorage, "temp"); // 避免的混乱命名 var storage1 = new ScopedStorage(rootStorage, "data1"); var storage2 = new ScopedStorage(rootStorage, "data2"); ``` #### 2. 存储性能优化 ```csharp // 好的做法:批量操作和缓存 public class OptimizedDataManager { private readonly IStorage _storage; private readonly Dictionary _writeBuffer = new(); public void QueueWrite(string key, T data) { _writeBuffer[key] = data; } public async Task FlushWritesAsync() { var tasks = _writeBuffer.Select(kvp => _storage.WriteAsync(kvp.Key, kvp.Value)); await Task.WhenAll(tasks); _writeBuffer.Clear(); } } // 避免:频繁的小写入 public class InefficientDataManager { public void UpdatePlayerStat(string stat, int value) { _storage.Write($"player/stats/{stat}", value); // 每次都写入磁盘 } } ``` ### 🔄 序列化优化 #### 1. 选择合适的序列化格式 ```csharp // 好的做法:根据需求选择格式 public class GameSerializer { // JSON:可读性好,调试方便 public string SerializeForDebug(object data) => JsonConvert.SerializeObject(data, Formatting.Indented); // 二进制:体积小,性能好 public byte[] SerializeForStorage(object data) => MessagePackSerializer.Serialize(data); // 压缩:减少存储空间 public byte[] SerializeWithCompression(object data) { var json = JsonConvert.SerializeObject(data); return Compress(Encoding.UTF8.GetBytes(json)); } } ``` #### 2. 自定义序列化逻辑 ```csharp public class PlayerInventory { public Dictionary Items { get; set; } = new(); [JsonIgnore] // 排除不需要序列化的属性 public int TotalWeight => Items.Sum(kvp => GetItemWeight(kvp.Key) * kvp.Value); [JsonProperty("total_items")] // 自定义序列化名称 public int TotalItems => Items.Values.Sum(); public bool ShouldSerializeItems() // 条件序列化 { return Items.Count > 0; } [OnDeserialized] // 反序列化后处理 private void OnDeserialized(StreamingContext context) { // 初始化默认值或执行验证 Items ??= new Dictionary(); } } ``` ### 🏭 模块设计模式 #### 1. 单一职责模块 ```csharp // 好的做法:模块职责单一 public class AudioModule : AbstractModule { // 只负责音频相关功能 } public class SaveModule : AbstractModule { // 只负责存档相关功能 } // 避免:功能过于庞大 public class GameModule : AbstractModule { // 音频、存档、UI、输入全部混在一起 } ``` #### 2. 模块间通信 ```csharp public class SaveModule : AbstractModule { public override void Install(IArchitecture architecture) { architecture.RegisterUtility(new SaveUtility()); } } public class PlayerModule : AbstractModule { public override void Install(IArchitecture architecture) { architecture.RegisterSystem(new PlayerSystem()); } public override void OnPhase(ArchitecturePhase phase, IArchitecture architecture) { if (phase == ArchitecturePhase.Ready) { // 通过事件进行模块间通信 this.RegisterEvent(OnPlayerDeath); } } private void OnPlayerDeath(PlayerDeathEvent e) { // 触发保存模块的事件 Context.SendEvent(new RequestAutoSaveEvent { Reason = "Player Death" }); } } ``` ## 性能特性 ### 📊 内存管理 - **缓存策略**:多层缓存减少磁盘 I/O - **延迟加载**:按需加载资源,减少内存占用 - **对象池化**:重用对象,减少 GC 压力 - **内存映射**:大文件使用内存映射技术 ### ⚡ 存储性能 ```csharp // 性能对比示例 public class StoragePerformanceTest { // 同步操作:简单直接 public void SyncWrite(IStorage storage, string key, object data) { storage.Write(key, data); // ~1-5ms } // 异步操作:非阻塞 public async Task AsyncWrite(IStorage storage, string key, object data) { await storage.WriteAsync(key, data); // ~0.1-1ms (不阻塞主线程) } // 批量操作:高吞吐量 public async Task BatchWrite(IStorage storage, Dictionary data) { var tasks = data.Select(kvp => storage.WriteAsync(kvp.Key, kvp.Value)); await Task.WhenAll(tasks); // ~10-50ms for 100 items } } ``` ### 🔄 序列化优化 - **格式选择**:JSON(可读性)vs 二进制(性能) - **压缩技术**:减少存储空间和网络传输 - **增量序列化**:只序列化变化的部分 - **版本控制**:向后兼容的数据迁移 --- ## 依赖关系 ```mermaid graph TD A[GFramework.Game] --> B[GFramework.Core] A --> C[GFramework.Core.Abstractions] A --> D[Newtonsoft.Json] A --> E[System.Text.Json] ``` ## 版本兼容性 - **.NET**: 6.0+ - **Newtonsoft.Json**: 13.0.3+ - **GFramework.Core**: 与 Core 模块版本保持同步 ## 许可证 本项目基于 Apache 2.0 许可证 - 详情请参阅 [LICENSE](../LICENSE) 文件。 --- **版本**: 1.0.0 **更新日期**: 2026-01-12