引导与世界 Bootstrap
在启动时组装一个 Framework World:装基础系统(输入 / 相机 / UI / 本地化 / 设置)、加载配置表、选择模式(Live / Sim),并提供统一更新入口。
一句话:三选一地创建 World —— FrameworkWorld / FrameworkModeBootstrap / 游戏自己的 ICustomBootstrap。
跨端数据加载契约(先读这段)
jar:file://),这两者都不能用 System.IO.File 直接读,必须先把数据 HTTP 进内存缓存。而读取发生在建 World 时的 System.OnCreate,所以预取必须先于建 World 完成。三种引导方式各自都有 Initialize / InitializeAsync。但无论哪种,全平台统一用 InitializeAsync 即可:
public sealed class GameBootstrap : MonoBehaviour
{
private async void Start()
{
// WebGL/Android:HTTP 预取进内存缓存;PC/iOS:no-op
await new FrameworkBootstrap().InitializeAsync("Game World");
// 之后照常:装 UI、进主菜单……
}
}
InitializeAsync 内部顺序:await StreamingAssets.PreloadAsync() → 建 World + 装系统(各 System.OnCreate 在这里读 Blob)→ FrameworkLifecycle.EnsureBootDataLoaded() 补加载入。宿主代码因此零平台分支。
更新阶梯(UpdateGroups)
固定顺序的 ComponentSystemGroup,全部挂在 SimulationSystemGroup 下的 UpdateGroup_Root 下:
SimulationSystemGroup
└── UpdateGroup_Root [After BeginSimulationEntityCommandBufferSystem]
├── UpdateGroup_A0 引导期:装单例、起管线、读启动配置
├── UpdateGroup_A1 数据期:配置加载、账号/状态、统计
├── UpdateGroup_A2 房间/场景期:房间进入、场景烘焙、环境
├── UpdateGroup_A3 玩法期:模拟、技能、AI、战斗(主体)
└── UpdateGroup_B9 表现期:UI 刷新、HUD、本地化刷新(最后跑)
UpdateGroup_B9 不能写 [UpdateBefore(typeof(LateSimulationSystemGroup))]——跨级排序会让 Entities 的 system sorter 抛 NRE。顺序关键:A0 装单例 → A1 加载配置 → A3 跑玩法 → B9 刷 UI,在 A3 之前查配置会查不到。三种引导方式
1. FrameworkWorld(installer 组合)
var host = new FrameworkWorld("Framework World");
World.DefaultGameObjectInjectionWorld = host.World;
host.Install(installers, BootMode); // installers: IEnumerable<IFrameworkInstaller>
host.Update(); // 每帧调
host.Dispose();
手动驱动:host.Update() 调 _rootGroup.Update()(没有就 _world.Update()),宿主要在 MonoBehaviour 里每帧调。UIManager 等 [DisableAutoCreation] 系统需手动 GetOrCreateSystemManaged 加进更新列表。
2. FrameworkModeBootstrap(按模式扫系统)
var boot = new FrameworkModeBootstrap();
await boot.InitializeAsync("Framework World"); // 内部 new World + AppendWorldToCurrentPlayerLoop
Update(),否则一帧跑两次。FrameworkWorld 才需要手动 Update()。3. 游戏自己的 ICustomBootstrap
框架的两个 bootstrap 都刻意不实现 ICustomBootstrap,避免被 Entities 自动扫描发现、与游戏自己的 bootstrap 冲突。游戏要自动引导就:在自己 ICustomBootstrap.Initialize 里 new FrameworkWorld(...),或把真正的引导放到 async void Start() 的 MonoBehaviour 里 await ...InitializeAsync(...)。
ICustomBootstrap.Initialize 是同步签名,无法 await。Unity 在 WebGL 上也无法等待预取——这是它本身的限制,不是框架能绕过的。请把框架装配放在 async void Start() 里。模式(Live / Sim)
static class SimulationBootstrap
{
public const int Live = 1;
public const int Sim = 2;
public static int Mode { get; set; } = 0;
public static bool IsSimulated => Mode == Sim;
}
系统用 [FrameworkModeOnly(模式)](仅该模式)或 [FrameworkMode(模式)](该模式才装)过滤;两者都没标记的系统在所有模式下都装。运行时用 RequireForUpdate<FrameworkMode_Live>() 按模式开关。
UI 适配与导航参数
UIManager.Setting(static)是 UI 适配 / 导航参数的唯一真源,引导期定制:
protected override void Configure(World world)
{
// UI 不是按 1920×1080 设计时才需要:
UIManager.Setting.ReferenceResolution = new Vector2(2560, 1080);
}
命令行 / 启动参数
GameCommandArgs 解析 Environment.GetCommandLineArgs():--account / --token / --appid / --serverip / --serverport / --lang / --width / --height / --fullscreen。
仅场景运行(调试用)
主工具栏中间区的 ▶ Scene 按钮可只跑当前场景、跳过框架引导,方便单独调试某个 Demo。机制:点按钮置位 BootstrapGate.ShouldSkip → 框架三个 Initialize 入口顶部查闸门为真即 return false → Entities 自动建默认世界。宿主只需把框架 Initialize 的返回值透传给 Entities 即可。
常见坑
UIManager/LocalizationBlobSystem等都是[DisableAutoCreation],只有引导期手动创建 / 扫描才进 World。- 顺序关键:A0 装单例 → A1 加载配置 → A3 跑玩法 → B9 刷 UI;A3 之前查配置查不到。
FrameworkModeBootstrap.Initialize已加进 player loop,勿再手动Update()。- WebGL / Android 上不要用
System.IO读 StreamingAssets,引导用InitializeAsync。