GFramework/GFramework.Game
2026-04-27 16:59:57 +08:00
..

GFramework.Game

GFramework.GameGFramework 面向游戏项目的运行时层。

它建立在 GFramework.CoreGFramework.Game.Abstractions 之上提供可直接落地的实现与基类覆盖静态内容配置、数据与存档、设置、场景路由、UI 路由、序列化、文件存储、状态机扩展等常见游戏运行时需求。

如果你的项目只需要“契约”而不想带入实现,请依赖 GFramework.Game.Abstractions。如果你的项目需要真正可运行的默认实现或基类,请依赖本包。

包定位

  • 面向使用者的默认运行时实现层,不是纯接口包。
  • 适合作为游戏项目启动层、基础设施层、引擎适配层之上的通用运行时底座。
  • 当前最成熟、最明确的能力集中在:
    • 静态内容配置:Config/
    • 数据与存档:Data/
    • 设置系统:Setting/
    • 场景与 UI 路由基类:Scene/UI/
    • 序列化与文件存储:Serializer/Storage/

与相邻包的关系

  • GFramework.Core
    • 本包直接依赖它。
    • 提供架构、上下文注入、事件、日志、系统/模型/utility 生命周期等底层能力。
  • GFramework.Game.Abstractions
    • 本包的上游契约层。
    • 本包中的 FileStorageSettingsModel<TRepository>SaveRepository<TSaveData>YamlConfigLoaderSceneRouterBaseUiRouterBase 等都在实现这里定义的接口。
  • GFramework.Game.SourceGenerators
    • 主要与配置系统配合使用。
    • 当你需要 schema 驱动的 YAML 配表时,运行时包是 GFramework.Game,生成时代码由 source generators 补齐。
  • 引擎适配包或项目内适配层
    • 本包提供的是“引擎无关”的核心逻辑和基类。
    • 真正和 Godot、Unity、MonoGame 等引擎对象打交道的工厂、根节点、资源注册表,通常在相邻引擎包或游戏项目内实现。
    • 典型项目里,配置文件 IO 会交给宿主适配层处理UI / Scene 的 factory 与 root 则继续由项目自己提供。

子系统地图

Config/

面向静态游戏内容的只读配置系统。

  • YamlConfigLoader
    • 从文件系统根目录加载 YAML 配置表,并注册到 IConfigRegistry
  • ConfigRegistry
    • 运行时配置表注册表
  • GameConfigBootstrap
    • Architecture 场景下的官方配置启动入口
  • GameConfigModule
    • Architecture 场景下的官方配置接入模块
  • InMemoryConfigTable<TKey, TValue>
    • 配置表默认只读承载
  • YamlConfigHotReloadOptions
    • 开发期热重载控制

这个子系统通常与 GFramework.Game.SourceGenerators 一起使用,而不是手写大量注册代码。

对应文档:

Data/

面向可写业务数据、设置持久化与存档槽位的仓库实现。

  • DataRepository
    • 一条 IDataLocation 对应一份持久化对象
  • UnifiedSettingsDataRepository
    • 把多个设置 section 聚合到单一文件中
  • SaveRepository<TSaveData>
    • 面向槽位存档,支持版本迁移链
  • SaveConfiguration
    • 槽位目录、文件名、前缀等约定

常见接法:

  • 设置持久化使用 UnifiedSettingsDataRepository
  • 存档使用 SaveRepository<GameSaveData>
  • 两者共用同一个底层存储 utility

对应文档:

Setting/

设置生命周期编排层。

  • SettingsModel<TRepository>
    • 管理 ISettingsData 实例、迁移、加载、保存、重置
    • 编排 applicator 的 Apply
  • SettingsSystem
    • 面向业务代码暴露更直接的系统级入口
  • Setting/Events/*
    • 设置初始化、应用、保存、重置相关事件

常见接法:

  • 在模型模块中创建 SettingsModel<ISettingsDataRepository>
  • 注册多个 applicator
  • 启动时先 InitializeAsync(),再 ApplyAll()
  • 退出时统一 SaveAll()

对应文档:

Storage/

面向本地文件系统的基础存储。

  • FileStorage
    • 基于目录与文件的 IStorage 实现
    • 负责路径清洗、细粒度锁、原子写入、层级 key 到目录结构的映射
  • ScopedStorage
    • 为底层存储增加前缀作用域

这部分能力经常被 DataRepositorySaveRepository<TSaveData>UnifiedSettingsDataRepository 复用。

对应文档:

Serializer/

  • JsonSerializer
    • 当前默认序列化实现
    • 同时可作为 ISerializerIRuntimeTypeSerializer

它通常先于存储和数据仓库被注册。

对应文档:

Scene/UI/

面向游戏导航的可复用基类,不直接绑定具体引擎。

  • SceneRouterBase
    • 依赖 ISceneFactoryISceneRoot
    • 提供栈式场景路由与转换处理管道
  • UiRouterBase
    • 依赖 IUiFactoryIUiRoot
    • 提供页面栈、Overlay/Modal/Toast 等层级 UI、输入动作分发、暂停联动
  • Scene/Handler/*UI/Handler/*
    • 默认转换处理器基类与日志处理器

常见接法:

  • 项目自定义 SceneRouter : SceneRouterBase
  • 项目自定义 UiRouter : UiRouterBase
  • 工厂、注册表、root 都由项目或引擎适配层提供

对应文档:

Routing/State/

  • Routing/RouterBase<TRoute, TContext>
    • Scene/UI 路由共享基类
  • State/GameStateMachineSystem
    • 对核心状态机系统的游戏向封装

这两部分一般被上层子系统消费,不是多数项目的第一接入点。

XML 阅读入口

下面这份目录视图汇总了 GFramework.Game 的类型级 XML 文档入口,用来帮助你确定运行时阅读顺序;更细的参数、返回值、异常和生命周期说明,建议继续回到具体类型与成员确认。

子系统 代表类型 阅读重点
Config/ YamlConfigLoaderConfigRegistryGameConfigBootstrapYamlConfigSchemaValidator 看 YAML 加载、schema 校验、模块接入与热重载边界
Data/ Storage/ Serializer/ DataRepositorySaveRepository<TSaveData>UnifiedSettingsDataRepositoryFileStorageJsonSerializer 看持久化布局、槽位存档、统一设置文件和底层序列化 / 存储实现
Setting/ SettingsModel<TRepository>SettingsSystemSettingsAppliedEvent<T> 看初始化、应用、保存、重置等设置生命周期编排
Scene/ UI/ Routing/ SceneRouterBaseUiRouterBaseSceneTransitionPipelineUiTransitionPipelineRouterBase<TRoute, TContext> 看路由基类、转换处理器和项目层需要自己提供的 factory / root 边界
Extensions/ Internal/ State/ DataLocationExtensionsVersionedMigrationRunnerGameStateMachineSystem 看辅助扩展、内部迁移执行逻辑和游戏态状态机封装

最小接入路径

下面按最常见的四种接入目标给出最短路径。

1. 只想先拿到文件存储

using GFramework.Core.Abstractions.Serializer;
using GFramework.Core.Abstractions.Storage;
using GFramework.Game.Serializer;
using GFramework.Game.Storage;

var serializer = new JsonSerializer();
IStorage storage = new FileStorage("GameData", serializer);

await storage.WriteAsync("player/profile", new { Name = "Alice", Level = 3 });

这里的 JsonSerializer 建议在组合根只创建并配置一次;如果需要自定义 JsonSerializerSettings 或 converters请在把它注册给 IStorageDataRepository 或架构 utility 之前完成。

如果你需要逻辑隔离,再包一层 ScopedStorage

var settingsStorage = new ScopedStorage(storage, "settings");

2. 接入设置和存档

运行时最小拼装顺序通常是:

  1. 注册 JsonSerializer
  2. 注册一个 IStorage 实现
  3. 注册 ISettingsDataRepository
  4. 创建并注册 SettingsModel<ISettingsDataRepository>
  5. 注册 applicator
  6. 注册 SettingsSystem
  7. 注册 ISaveRepository<TSaveData>

示意代码:

var serializer = new JsonSerializer();
var storage = new FileStorage("GameData", serializer);

architecture.RegisterUtility(serializer);
architecture.RegisterUtility<IStorage>(storage);

architecture.RegisterUtility<ISettingsDataRepository>(
    new UnifiedSettingsDataRepository(
        storage,
        serializer,
        new DataRepositoryOptions { BasePath = "settings", AutoBackup = true }));

architecture.RegisterModel(
    new SettingsModel<ISettingsDataRepository>(
        new MySettingsLocationProvider(),
        architecture.Context.GetUtility<ISettingsDataRepository>())
        .RegisterApplicator(new MyAudioSettingsApplicator()));

architecture.RegisterSystem<ISettingsSystem>(new SettingsSystem());

architecture.RegisterUtility<ISaveRepository<MySaveData>>(
    new SaveRepository<MySaveData>(
        storage,
        new SaveConfiguration
        {
            SaveRoot = "saves",
            SaveSlotPrefix = "slot_",
            SaveFileName = "save.json"
        }));

启动时:

await settingsModel.InitializeAsync();
await settingsSystem.ApplyAll();

退出前:

await settingsSystem.SaveAll();

在 Godot 项目中也可以沿用同一思路,只是底层存储通常换成宿主侧适配实现。

3. 接入静态 YAML 配置

如果你不走 Architecture 生命周期,直接使用 GameConfigBootstrap

var bootstrap = new GameConfigBootstrap(
    new GameConfigBootstrapOptions
    {
        RootPath = contentRootPath,
        ConfigureLoader = static loader =>
        {
            loader.RegisterAllGeneratedConfigTables();
        }
    });

await bootstrap.InitializeAsync();

var registry = bootstrap.Registry;

如果你走 Architecture,优先使用 GameConfigModule,并在较早阶段安装。

这一能力几乎总是与 source generators 绑定使用。目录、schema、生成器与热重载约定请直接看

4. 接入 Scene / UI 路由

这里的最小前提不是“直接 new 一个 router”而是先补齐运行时依赖

  • ISceneFactory / IUiFactory
  • ISceneRoot / IUiRoot
  • 具体页面或场景行为实现

然后让项目自己的 router 继承基类:

public sealed class MySceneRouter : SceneRouterBase
{
    protected override void RegisterHandlers()
    {
        RegisterHandler(new LoggingTransitionHandler());
    }
}

public sealed class MyUiRouter : UiRouterBase
{
    protected override void RegisterHandlers()
    {
        RegisterHandler(new GFramework.Game.UI.Handler.LoggingTransitionHandler());
    }
}

这类 router 适合作为你的项目层或引擎适配层代码,而不是直接修改本包。

典型项目分层方式

典型项目对本包的使用大致分成三层:

  • 配置
    • 项目级配置宿主类型使用生成表元数据与 YAML loader 完成配置注册
  • 设置与存档
    • 项目层 utility 模块注册序列化器、底层存储、UnifiedSettingsDataRepositorySaveRepository<GameSaveData>
    • 项目层 model 模块创建 SettingsModel<ISettingsDataRepository> 并注册 applicator
  • 路由
    • 项目自定义 SceneRouterBase / UiRouterBase 的派生类型

这说明本包更适合做“游戏基础设施层”,而不是把所有引擎对象耦死在包内部。

文档入口

什么时候不该直接依赖本包

以下场景优先考虑只依赖 GFramework.Game.Abstractions

  • 你在做纯领域层、协议层或可复用 feature 包,只想引用接口和数据契约
  • 你已经有自己的配置、存储、路由实现,只想复用统一契约
  • 你不希望业务程序集带入 Newtonsoft.JsonYamlDotNet 等运行时依赖