当前位置: 首页 > news >正文

YooAsset运行机制

Unity 游戏启动流程(Boot脚本)

功能概述:

  • 初始化游戏运行环境(帧率、后台运行等)
  • 初始化核心系统(事件系统、资源系统)
  • 加载并显示补丁更新界面
  • 启动补丁更新流程(异步)
  • 更新完成后切换到主场景
public class Boot : MonoBehaviour
{/// <summary>/// 资源系统运行模式/// </summary>public EPlayMode PlayMode = EPlayMode.EditorSimulateMode;void Awake(){Debug.Log($"资源系统运行模式:{PlayMode}");Application.targetFrameRate = 60;Application.runInBackground = true;DontDestroyOnLoad(this.gameObject);}IEnumerator Start(){// 游戏管理器GameManager.Instance.Behaviour = this;// 初始化事件系统UniEvent.Initalize();// 初始化资源系统YooAssets.Initialize();// 加载补丁更新页面var go = Resources.Load<GameObject>("PatchWindow");GameObject.Instantiate(go);// 开始补丁更新流程var operation = new PatchOperation("DefaultPackage", PlayMode);YooAssets.StartOperation(operation);yield return operation;// 设置默认的资源包var gamePackage = YooAssets.GetPackage("DefaultPackage");YooAssets.SetDefaultPackage(gamePackage);// 切换到主页面场景SceneEventDefine.ChangeToHomeScene.SendEventMessage();}
}

        如果你希望支持纯离线模式(比如单机游戏不更新),通常会在 Boot.Start() 中判断 PlayMode跳过 PatchOperation 直接进入游戏。

补丁更新操作(异步状态机)PatchOperation

使用 UniFramework.Machine.StateMachine 构建一个状态机,包含多个状态节点(FsmXXX):

状态节点功能
FsmInitializePackage初始化资源包
FsmRequestPackageVersion请求远程版本信息
FsmUpdatePackageManifest更新清单文件
FsmCreateDownloader创建下载器
FsmDownloadPackageFiles下载资源文件
FsmDownloadPackageOver下载完成处理
FsmClearCacheBundle清理缓存
FsmStartGame准备进入游戏
using UnityEngine;
using UniFramework.Machine;
using UniFramework.Event;
using YooAsset;public class PatchOperation : GameAsyncOperation
{private enum ESteps{None,Update,Done,}private readonly EventGroup _eventGroup = new EventGroup();private readonly StateMachine _machine;private readonly string _packageName;private ESteps _steps = ESteps.None;public PatchOperation(string packageName, EPlayMode playMode){_packageName = packageName;// 注册监听事件_eventGroup.AddListener<UserEventDefine.UserTryInitialize>(OnHandleEventMessage);_eventGroup.AddListener<UserEventDefine.UserBeginDownloadWebFiles>(OnHandleEventMessage);_eventGroup.AddListener<UserEventDefine.UserTryRequestPackageVersion>(OnHandleEventMessage);_eventGroup.AddListener<UserEventDefine.UserTryUpdatePackageManifest>(OnHandleEventMessage);_eventGroup.AddListener<UserEventDefine.UserTryDownloadWebFiles>(OnHandleEventMessage);// 创建状态机_machine = new StateMachine(this);_machine.AddNode<FsmInitializePackage>();_machine.AddNode<FsmRequestPackageVersion>();_machine.AddNode<FsmUpdatePackageManifest>();_machine.AddNode<FsmCreateDownloader>();_machine.AddNode<FsmDownloadPackageFiles>();_machine.AddNode<FsmDownloadPackageOver>();_machine.AddNode<FsmClearCacheBundle>();_machine.AddNode<FsmStartGame>();_machine.SetBlackboardValue("PackageName", packageName);_machine.SetBlackboardValue("PlayMode", playMode);}protected override void OnStart(){_steps = ESteps.Update;_machine.Run<FsmInitializePackage>();}protected override void OnUpdate(){if (_steps == ESteps.None || _steps == ESteps.Done)return;if (_steps == ESteps.Update){_machine.Update();}}protected override void OnAbort(){}public void SetFinish(){_steps = ESteps.Done;_eventGroup.RemoveAllListener();Status = EOperationStatus.Succeed;Debug.Log($"Package {_packageName} patch done !");}/// <summary>/// 接收事件/// </summary>private void OnHandleEventMessage(IEventMessage message){if (message is UserEventDefine.UserTryInitialize){_machine.ChangeState<FsmInitializePackage>();}else if (message is UserEventDefine.UserBeginDownloadWebFiles){_machine.ChangeState<FsmDownloadPackageFiles>();}else if (message is UserEventDefine.UserTryRequestPackageVersion){_machine.ChangeState<FsmRequestPackageVersion>();}else if (message is UserEventDefine.UserTryUpdatePackageManifest){_machine.ChangeState<FsmUpdatePackageManifest>();}else if (message is UserEventDefine.UserTryDownloadWebFiles){_machine.ChangeState<FsmCreateDownloader>();}else{throw new System.NotImplementedException($"{message.GetType()}");}}
}

FsmInitializePackage(有限状态机(FSM)的流程控制架构

        这段代码是 热更新/资源管理系统中的一个状态节点(State Node),它实现了 IStateNode 接口,属于一个 基于有限状态机(FSM)的流程控制架构。其核心作用是:

该状态节点负责:

  1. 从状态机的“黑板”(Blackboard)中读取:
    • 资源包名称(PackageName
    • 当前运行模式(PlayMode:编辑器模拟、离线、联机、WebGL 等)
  2. 使用 YooAsset(一个 Unity 资源管理框架)创建并初始化对应的资源包(Package)。
  3. 根据不同平台和运行模式,配置不同的文件系统参数(如本地内置资源、缓存、远程服务器等)。
  4. 异步执行初始化操作(InitializeAsync)。
  5. 初始化成功后,切换状态机到下一个状态FsmRequestPackageVersion(请求资源包版本)。
  6. 若失败,则发送失败事件(InitializeFailed),通常用于弹出错误提示。
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UniFramework.Machine;
using YooAsset;internal class FsmInitializePackage : IStateNode
{private StateMachine _machine;void IStateNode.OnCreate(StateMachine machine){_machine = machine;}void IStateNode.OnEnter(){PatchEventDefine.PatchStepsChange.SendEventMessage("初始化资源包!");GameManager.Instance.StartCoroutine(InitPackage());}void IStateNode.OnUpdate(){}void IStateNode.OnExit(){}private IEnumerator InitPackage(){var playMode = (EPlayMode)_machine.GetBlackboardValue("PlayMode");var packageName = (string)_machine.GetBlackboardValue("PackageName");// 创建资源包裹类var package = YooAssets.TryGetPackage(packageName);if (package == null)package = YooAssets.CreatePackage(packageName);// 编辑器下的模拟模式InitializationOperation initializationOperation = null;if (playMode == EPlayMode.EditorSimulateMode){var buildResult = EditorSimulateModeHelper.SimulateBuild(packageName);var packageRoot = buildResult.PackageRootDirectory;var createParameters = new EditorSimulateModeParameters();createParameters.EditorFileSystemParameters = FileSystemParameters.CreateDefaultEditorFileSystemParameters(packageRoot);initializationOperation = package.InitializeAsync(createParameters);}// 单机运行模式if (playMode == EPlayMode.OfflinePlayMode){var createParameters = new OfflinePlayModeParameters();createParameters.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters();initializationOperation = package.InitializeAsync(createParameters);}// 联机运行模式if (playMode == EPlayMode.HostPlayMode){string defaultHostServer = GetHostServerURL();string fallbackHostServer = GetHostServerURL();IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);var createParameters = new HostPlayModeParameters();createParameters.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters();createParameters.CacheFileSystemParameters = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices);initializationOperation = package.InitializeAsync(createParameters);}// WebGL运行模式if (playMode == EPlayMode.WebPlayMode){
#if UNITY_WEBGL && WEIXINMINIGAME && !UNITY_EDITORvar createParameters = new WebPlayModeParameters();string defaultHostServer = GetHostServerURL();string fallbackHostServer = GetHostServerURL();string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE"; //注意:如果有子目录,请修改此处!IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);createParameters.WebServerFileSystemParameters = WechatFileSystemCreater.CreateFileSystemParameters(packageRoot, remoteServices);initializationOperation = package.InitializeAsync(createParameters);
#elsevar createParameters = new WebPlayModeParameters();createParameters.WebServerFileSystemParameters = FileSystemParameters.CreateDefaultWebServerFileSystemParameters();initializationOperation = package.InitializeAsync(createParameters);
#endif}yield return initializationOperation;// 如果初始化失败弹出提示界面if (initializationOperation.Status != EOperationStatus.Succeed){Debug.LogWarning($"{initializationOperation.Error}");PatchEventDefine.InitializeFailed.SendEventMessage();}else{_machine.ChangeState<FsmRequestPackageVersion>();}}/// <summary>/// 获取资源服务器地址/// </summary>private string GetHostServerURL(){//string hostServerIP = "http://10.0.2.2"; //安卓模拟器地址string hostServerIP = "http://127.0.0.1";string appVersion = "v1.0";#if UNITY_EDITORif (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)return $"{hostServerIP}/CDN/Android/{appVersion}";else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)return $"{hostServerIP}/CDN/IPhone/{appVersion}";else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)return $"{hostServerIP}/CDN/WebGL/{appVersion}";elsereturn $"{hostServerIP}/CDN/PC/{appVersion}";
#elseif (Application.platform == RuntimePlatform.Android)return $"{hostServerIP}/CDN/Android/{appVersion}";else if (Application.platform == RuntimePlatform.IPhonePlayer)return $"{hostServerIP}/CDN/IPhone/{appVersion}";else if (Application.platform == RuntimePlatform.WebGLPlayer)return $"{hostServerIP}/CDN/WebGL/{appVersion}";elsereturn $"{hostServerIP}/CDN/PC/{appVersion}";
#endif}/// <summary>/// 远端资源地址查询服务类/// </summary>private class RemoteServices : IRemoteServices{private readonly string _defaultHostServer;private readonly string _fallbackHostServer;public RemoteServices(string defaultHostServer, string fallbackHostServer){_defaultHostServer = defaultHostServer;_fallbackHostServer = fallbackHostServer;}string IRemoteServices.GetRemoteMainURL(string fileName){return $"{_defaultHostServer}/{fileName}";}string IRemoteServices.GetRemoteFallbackURL(string fileName){return $"{_fallbackHostServer}/{fileName}";}}
}

流程机制详解

1. 状态机集成(FSM Integration)

  • 实现了 IStateNode 接口(来自 UniFramework.Machine),这是 UniFramework 提供的状态机节点标准。
  • 在 OnEnter() 中启动协程 InitPackage(),这是状态进入时的主逻辑。
  • 成功后调用 _machine.ChangeState<FsmRequestPackageVersion>(),实现状态转移,这是 FSM 的典型行为。

这里详细说明下IStateNode:

public interface IStateNode
{void OnCreate(StateMachine machine);  // 状态被创建时调用(绑定状态机)void OnEnter();                       // 进入该状态时调用(一次)void OnUpdate();                      // 每帧调用(可选,用于持续逻辑)void OnExit();                        // 离开该状态时调用(一次)
}
方法调用时机典型用途特性
OnCreate状态首次被 StateMachine.AddNode<T>() 注册后创建实例时缓存 StateMachine 引用、初始化内部变量只调用一次,用于“注入上下文”
OnEnter状态机切换到该状态时启动逻辑(如协程、加载、发送事件)每次进入都调用,是状态的“入口”
OnUpdate每帧(或每 tick)状态机更新时持续检测条件、处理输入、计时等可选实现,若无持续逻辑可留空
OnExit状态机即将切换到其他状态前清理资源、取消协程、保存状态每次离开都调用,是状态的“出口”

在你的 FsmInitializePackage 中:

  • OnCreate:保存 _machine 引用
  • OnEnter:启动 InitPackage() 协程(核心逻辑)
  • OnUpdate:留空(因为初始化是异步一次性操作)
  • OnExit:留空(无需要清理的内容)

2. 协程 InitPackage():按模式初始化

1:获取上下文参数
var playMode = (EPlayMode)_machine.GetBlackboardValue("PlayMode");
var packageName = (string)_machine.GetBlackboardValue("PackageName");
  • 从状态机的“黑板(Blackboard)”中读取启动时传入的配置

步骤 2:获取或创建 Package
var package = YooAssets.TryGetPackage(packageName);
if (package == null)package = YooAssets.CreatePackage(packageName);
  • 确保目标资源包存在

步骤 3:根据 playMode 分支处理
模式行为是否联网用途
EditorSimulateMode调用 EditorSimulateModeHelper.SimulateBuild(),从本地模拟构建目录加载❌ 否编辑器调试,模拟热更新流程
OfflinePlayMode使用内置资源(StreamingAssets❌ 否完全离线单机游戏
HostPlayMode从远程服务器(CDN)下载资源,使用缓存系统✅ 是标准在线热更新
WebPlayMode针对 WebGL(或微信小游戏)的特殊文件系统✅ 是(WebGL) / 特殊存储(小游戏)Web 或小程序平台

补充:联机模式(HostPlayMode)详解
string defaultHostServer = GetHostServerURL();
IRemoteServices remoteServices = new RemoteServices(defaultHostServer, fallbackHostServer);
var createParameters = new HostPlayModeParameters();
createParameters.BuildinFileSystemParameters = ...; // 内置资源(如初始资源)
createParameters.CacheFileSystemParameters = ...;  // 远程资源缓存到本地
initializationOperation = package.InitializeAsync(createParameters);
  • BuildinFileSystem:读取 StreamingAssets 中的初始资源(随包发布)
  • CacheFileSystem:将从服务器下载的更新资源缓存到 Application.persistentDataPath
  • IRemoteServices:提供资源文件的 URL 拼接逻辑(主地址 + 备用地址)

🔥 这是 远程热更新的核心:初始化阶段就建立了“本地缓存 + 远程下载”的混合文件系统。


3. GetHostServerURL():动态构建 CDN 地址

string hostServerIP = "http://127.0.0.1"; // ← 本地测试服务器
string appVersion = "v1.0";
return $"{hostServerIP}/CDN/Android/{appVersion}";
  • 根据 构建平台(Android/iOS/WebGL/PC) 返回对应 CDN 路径
  • 当前配置为 127.0.0.1,说明是 本地测试(需运行本地 HTTP 服务器)
  • 正式上线时应改为真实 CDN 地址,如 https://cdn.yourgame.com

⚠️ 注意:这段代码硬编码了 IP 和版本号,实际项目中通常从配置文件或远程配置接口获取。


4. 初始化结果处理

yield return initializationOperation;if (initializationOperation.Status != EOperationStatus.Succeed)
{PatchEventDefine.InitializeFailed.SendEventMessage();
}
else
{_machine.ChangeState<FsmRequestPackageVersion>(); // 进入下一步
}
  • 等待异步初始化完成
  • 成功则进入 请求远程版本号 阶段(热更新流程继续)
  • 失败则通知 UI(用户可能看到“初始化失败,请检查网络”)

RemoteServices 

RemoteServices 类的具体作用:

1. 存储两个服务器地址

private readonly string _defaultHostServer;   // 主 CDN 地址
private readonly string _fallbackHostServer;  // 备用 CDN 地址

2. 实现两个关键方法

方法作用
GetRemoteMainURL(fileName)返回主服务器上的资源完整 URL
GetRemoteFallbackURL(fileName)返回备用服务器上的资源完整 URL

// 内部实现:真正负责拼接远程地址的服务类
private class RemoteServices : IRemoteServices
{// 默认主站地址(CDN 主节点)private readonly string _defaultHostServer;// 备用站地址(CDN 备节点或灾备域名)private readonly string _fallbackHostServer;/// <summary>/// 构造远程服务实例/// </summary>/// <param name="defaultHostServer">主站基准地址,例如 "https://cdn.main.example.com"</param>/// <param name="fallbackHostServer">备用站基准地址,例如 "https://cdn.backup.example.com"</param>public RemoteServices(string defaultHostServer, string fallbackHostServer){_defaultHostServer = defaultHostServer;_fallbackHostServer = fallbackHostServer;}// 显式接口实现:返回主站完整文件链接string IRemoteServices.GetRemoteMainURL(string fileName){return $"{_defaultHostServer}/{fileName}";}// 显式接口实现:返回备用站完整文件链接string IRemoteServices.GetRemoteFallbackURL(string fileName){return $"{_fallbackHostServer}/{fileName}";}
}

IRemoteServices接口:

namespace YooAsset
{public interface IRemoteServices{/// <summary>/// 获取主资源站的资源地址/// </summary>/// <param name="fileName">请求的文件名称</param>string GetRemoteMainURL(string fileName);/// <summary>/// 获取备用资源站的资源地址/// </summary>/// <param name="fileName">请求的文件名称</param>string GetRemoteFallbackURL(string fileName);}
}

补充说明:补丁更新操作中   

状态机和有限状态机

  • StateMachine 是一个自定义类,用于管理一组状态(节点)。
  • 每个状态(如 FsmInitializePackage)是一个具体的类,代表 FSM 中的一个状态。

2. 你代码中的 _machine 是什么

_machine = new StateMachine(this);
_machine.AddNode<FsmInitializePackage>();
// ... 添加多个状态节点

从命名和用法来看:

  • StateMachine 是一个自定义类,用于管理一组状态(节点)。
  • 每个状态(如 FsmInitializePackage)是一个具体的类,代表 FSM 中的一个状态。
  • 状态之间通过某种机制(可能在每个状态内部调用 _machine.TransitionTo<NextState>())进行转移。

并且从代码结构上看:

判断依据:

特征是否满足说明
有限个状态只添加了 8 个明确的状态类
明确的状态转移✅(隐含)虽然没看到转移代码,但每个状态类内部通常会决定下一步跳转
同一时间只处在一个状态✅(通常如此)标准 FSM 行为
状态行为封装每个 FsmXXX 类封装了该状态的逻辑

因此,它的结构就是 FSM,只是用类和泛型做了封装,使其更模块化、可维护。

http://www.dtcms.com/a/496702.html

相关文章:

  • CC12-拆分词句
  • 室内设计网站参考手机能建设网站吗
  • 做网站宁波有什么的网络公司网页设计与制作公告栏
  • 直播美颜SDK功能开发实录:自然妆感算法、人脸跟踪与AI美颜技术
  • 建设网站怎么查明细想开广告公司怎么起步
  • Monkey 综合运用参考
  • 如何做网站内页制作一个视频网站
  • seo网站首页推广跨境电商要投资多少钱
  • html5导航网站邮箱网址查询
  • 中药饮片供应商的市场机会及其重要性是什么?
  • 说一下JM有哪些垃圾回收器?
  • 深州网站网站建设公司哪家好要选磐石网络
  • 做网站工资年新多少在广东专门做图的网站
  • 亦庄网站开发html网页制作超链接
  • 价格低英语翻译网络优化面试问题
  • 【文档】部署 alertmanager
  • 舟山公司网站建设域名访问网站的知识
  • 商城网站建设浩森宇特扬中网站网站建设
  • [MLflow] 追踪 | 运行与实验 | 创建首个MLflow实验
  • 网站注销备案软装设计师常用网站
  • 织梦网站动态网站制作 php
  • 网络电商培训课程网站设计安装wordpress教程
  • 电子商务网站的建设视频网站排名查询工具
  • 学校门户网站建设必要性电子 公司 网站建设
  • 制作网站培训网页设计页面设计
  • 电商直播平台网站开发公司企业官网建设
  • 广州网站优化招聘企业推广语
  • 网站制作后续维护网站维护包括
  • 生存分析任务建模以及损失函数
  • 中国正规的加盟网站网站设计的风格有哪些