
声明
出于作者本人的能力限制,项目中可能有一些使用不当或者设计不合理的地方,欢迎各位大佬沟通指教;
但是只是设计理念不同的话,只能回一句:求同存异,不喜勿喷,栓Q~
设计本框架的初衷
原来在前司的时候,由于公司内做的项目类型比较多,公司本身又比较小,所以自己就积累下来了一些轮子(真不想重复造轮子,但是有些工具实在是太庞大了),这是其一;
到了新公司以后(2026.5)发现,母公司是石油企业发家的,然后转型互联网-游戏,算是一家中型游戏公司吧。但是,即便游戏部门有一百多号人,也有自己的技术中台,公司依然没有自己的核心框架供每个项目组使用,因此导致了各个项目中要独立编写自己的框架,浪费时间(哪怕是主程带了自己的框架),且技术水平参差不齐。然后在面试的时候也发现,很多中小型公司(初创型等)也缺少一些核心框架,有的有技术中台支持,有的没有,这是其二;
随着AI编程能力的飞跃,很多以前没有落地过的设计理念,可以在AI这里得到快速验证,对于以前只闻其大名(眼睛会了),但是从来没有实际上手开发过的开发理念或者名词自己也有了手替,不出意外的话,(看完以后,在眼睛会了的基础上)就等于手会了,这是其三。
设计需求
基于以上几点,我认为此时就缺少一个框架专为中小型公司(专业一点应该叫企业是吧~)服务,要做到什么事呢?
- 支持各个平台
- 要有基础的功能性框架(并且可以动态加载、卸载,不过这里动态安装、卸载程序集包暂未实现2026.8.8,只支持动态加载、卸载),包括:
- 资源管理
- 热更新(资源、代码)
- 网络
- 数据序列化
- 基础的本地存储与加密等
- 前后端同步支持且上手简单(重要)
- 为什么说这很重要呢?
- 因为其实很多中小型公司其实很多时候后端人员分不出来,或者再小一点的,压根就没有后端开发人员,然后很多客户端开发对于网络开发又不擅长,甚至包括一些后端,其实对于网络的优化也不是特别擅长(当然,我也是在逐步学习当中,力求成为一个优秀的网络开发设计师)。
- 可选的基础服务、支持扩展(也重要)
- 很多公司,其实有时候碰到好的框架设计,不是不想用,而是:
- 1、学习成本太高
- 2、框架太重,很多东西不想用,但是融合在一起不是很好拆开
- 有时候想扩展一些功能但是与框架耦合很重的时候确实不太方便
- 很多公司,其实有时候碰到好的框架设计,不是不想用,而是:
设计实现
所以,为了迎合以上的需求,本框架做了以下设计:
- 基于模块化的设计,将项目中的各个功能划分以下几种:
- 服务(Service):指的是本项目框架默认提供的基础服务,包括网络框架、资源加载等
- 模块(Module):指的是项目中的一些公共服务功能,依赖于基础服务,又不是在业务层的
- 组件(Component):指的是业务使用的一些公共组件,比如房间管理组件等
- 全局模块:
- 内置Global类可以加载任意的Service、Module、Component,并且获取的是对应的接口(让调用者可以不关心实现,同时开发者又可以在启动配置里面配置服务启用哪种实现)
- 自主设计的MTask:
- 这里真不是为了设计一个MTask用来装X而重复造组件的行为,主要是为了解决一个Task/Unitask的痛点:
- CancellationToken的无限传递。。。
- 即便是在Unitask中,异步取消流程注入到MonoBehaviour中,子流程也需要通过传入根节点的CancellationToken或者 new()一个 CancellationTokenSource 来取消,真的痛!
- 设计了一个MTask,使用框架自带的服务以及整个流程中,默认会进行MTask的树形管理,上层的MTask被中断后,会直接取消所有子节点流程(可以手动选择忽略取消)
- 目前的MTask还在继续完善中,后续会借鉴UniTask的设计思路,加入PlayerLoop等设计思路。
- 这里真不是为了设计一个MTask用来装X而重复造组件的行为,主要是为了解决一个Task/Unitask的痛点:
- 项目启动配置(项目中自带MiniCore编辑器菜单),主要有:
- 项目启动配置:
- 勾选项目用到的服务(如最顶上的图)。(后续想做成各种包的形式,动态加载,不勾选的直接不往项目中引用)
- 项目能力目录:自动扫描并列出项目中已经实现的Service、Module、Component等
- UI:
- RootCanvas:快速生成项目UI框架用到的Canvas管理预制体(无需手动引用,运行时自动加载)
- CreateWindow:快速生成符合项目框架的MVP结构的UI类
- Protocol:将pb数据转成符合框架使用的cs类
- Build:
- 全量(GenerateAll)构建HybridCLR生成类+自动打包YooAssets预制体并一键拷贝
- 增量(CompileTarget)构建HybridCLR生成类+自动打包YooAssets预制体并一键拷贝。主要用于快速开发真机测试。
- Performance:查看、对比测试数据
- ….
- 项目启动配置:
- 对于中小型项目需要同时使用前后端开发:可以直接使用DedicatedServer开发,直接写好前后端对接流程,然后打不同的包即可(不过如果要接入数据库等,可以单独再写一个存储数据的后端或者直接接入数据库的连接件),在投入不高的情况下快速验证游戏玩法,不行就赶紧撤,数据上去,开始赚大发了再换更重型的ET、FT之类的。
快速开始:
1. 打开项目
使用 Unity 2021.3.45f2 打开工程,等待脚本编译完成。Build Settings 中使用 Assets/Scenes/HotUpdateScene.unity 作为启动场景。
2. 配置服务
打开 MiniCore > 项目启动配置:
- 在 AppService 区按接口选择一个 Provider,或选择“不启用”;新接口默认关闭。
- 仅为服务填写非敏感启动参数,例如超时、重试次数或对象池大小。
- 在右侧“项目能力目录”查看可用的 Service、AppModule 与已标注职责的普通
AComponent。 - 点击“保存启动参数并生成代码”,等待 Unity 编译完成。
配置保存于 Assets/Settings/MiniCoreStartupSettings.asset,生成代码位于 Assets/Scripts/MiniCore/HotUpdate/Generated/Startup/MiniCoreStartup.Generated.cs。
未选择 Provider 的服务不会自动注册或启动;它的代码、程序集和资源仍会保留在项目及最终包体中。通过 Global.GetService<T> 获取未启用服务会报错;可选服务请使用 Global.TryGetService<T> 判断。
3. 编写项目入口
在 Assets/Scripts/MiniCore/HotUpdate/Entry/GameStartup.cs 中实现项目的首个业务动作:客户端可进入登录或主界面,服务端可启动监听、加载配置或初始化业务服务。
public sealed class GameStartup : AGameStartup
{
public override async MTask StartAsync()
{
if (Application.isBatchMode)
{
INetworkService network = Global.GetService<INetworkService>(this);
await network.StartKcpServerAsync("0.0.0.0", 20000);
return;
}
// 客户端首个业务动作。
}
}
4. 使用服务与组件
启动配置选择的系统服务只能按接口使用,并在 owner 不再需要时归还引用;局部临时流程仍可使用 GlobalScope 管理普通组件生命周期。
IResourceService resources = Global.GetService<IResourceService>(this);
MiniCore.UI.IUIService ui = Global.GetService<MiniCore.UI.IUIService>(this);
await resources.PreloadAssetAsync<GameObject>("UI/Login");
await ui.OpenAsync<LoginWindow>();
Global.ReleaseAll(this);
using (GlobalScope battle = Global.CreateScope("Battle"))
{
TimerComponent timer = battle.GetOrAdd<TimerComponent>();
}
5. 新增网络消息
- 在根目录
Proto/中新增或修改业务.proto。 - 在 Unity 执行
MiniCore > Protocol > Generate All。 - 在
Assets/Scripts/MiniCore/HotUpdate编写AMHandler<T>或ARpcHandler<TRequest, TResponse>。 - 等待编译完成,Opcode 与 Handler 注册表会自动同步。
6. 编写异步业务
公开异步方法返回 MTask。普通类中的 MTask 会自动加入当前父任务;组件、服务、模块和 AMTaskBehaviour 则是自动取消边界。不要为业务链路传递 CancellationToken、创建启动 Handle 或每次切线程都新建线程。
public async MTask RefreshAsync()
{
await MTask.SwitchTo(MTaskExecutors.ThreadPool);
CalculateWithoutUnityAccess();
await MTask.SwitchTo(MTaskExecutors.Unity);
ApplyToView();
}
运行期组件释放会先调用 OnDisposing() 关闭 Socket 等阻塞 I/O,再等待任务 finally 并调用 OnDispose()。关闭 Player 或停止 Play Mode 使用快速退出,不阻塞主线程等待后台任务;详细语义见下方 MTask 文档。
典型启动链
HotUpdateScene
→ UpdateMainWindow
→ YooAsset 初始化与资源更新
→ HybridCLR AOT 元数据加载
→ MiniCore.HotUpdate.dll 加载
→ MiniCoreStartup.StartAsync()
→ 自动生成的统一 AppService 注册代码
→ GameStartup.StartAsync()
框架github:https://github.com/ForGetMyGirl/MiniCore
后续要开发的内容:
- 当前已实现MVP框架,但是Codex这个笨蛋在Demo项目中没有正确使用MVP这3个类,后续会做成skill让它按照正确的使用方式去修正。
- 同样是Demo项目中,同样是Codex这个笨蛋,把很多类都放到一个类文件中了,这个后续也会放进编码规范的skill中进行拆分。
- 后续为了支持WebGL、微信小游戏、抖音小游戏等(这个会尽快实现,毕竟需求量有点大),会把当前MTask的执行器进行修改,在这些web类型平台上会只支持单线程(主线程)并对任务进行分片;并且会引入Websocket等进行网路通信(这个再MTask改造完成后 接入非常简单,实现INetworkTransport接口即可)
- ….