HybridCLR+Adressable+Springboot热更
本文章会手把手教大家如何搭建HybridCLR+Adressable+Springboot热更。
创作不易,动动发财的小手点个赞。
安装华佗
首先我们按照官网的快速上手指南搭建一个简易的项目:
快速上手 | HybridCLR
注意在热更的代码里添加程序集。把用到的工具放到程序集里。

local程序集:这个程序集不热更,跟游戏一起打包:
注意:不能把热更的代码放到local程序集里,local程序集只能调用非热更代码。

安装Adressable:

然后开始配置Adressable:
系统配置,没什么需要强调的,根据需求点。

注意,我是用的是自己的config动态修改打包的位置,配置文件在下面:
自定义远端:

使用host(看后面):
这个也是根据需求点就行。
如果你没有自己的服务器,可以使用Addressable自带的host工具(注意修改配置文件里的信息):

Addressable和工具的config文件:
public class FrameworkConfig
{public static string DownLoadPath = "D:/Desktop/local/test";//打包后,Adressable缓存地址(外部{}引用)public static string RemotePath = "http://47.xxx.43.98/files/";//Adressable的服务器地址(外部{}引用)public static string BaseUrl = "http://47.xxx.43.98/";public static string UploadPath = "http://47.xxx.43.98/upload";//打好的Addressable包的上传的地址public static string DeletePath = "http://47.xxx.43.98/files";//删除服务器远端仓库的请求地址public static string LoginPath = "http://47.xxx.43.98/login";//登录服务器远端仓库的请求地址public static string LogoutPath = "http://47.xxx.43.98/logout";//登出服务器远端仓库的请求地址public static string PackPath=@"D:\GameClient\game-client\client\ServerData\StandaloneWindows64";//打好的本地Addressable包的地址// public static string RemoteBuildPath = "ServerData/[BuildTarget]";Build地址需要在Addressable里改public static string DLLName = "HotUpdate.dll.bytes";//热更dll在group中的索引public static string StartSceneName="Assets/HotUpdate/Scenes/StartScene.unity";//更新后启动场景的group中的索引public static string DLLPath = @"../HybridCLRData/HotUpdateDlls/StandaloneWindows64/HotUpdate.dll";//热更dll打包后迁移前的位置public static string NewDLLPath = "HotUpdate/Dlls";//热更dll打包后迁移后的位置public static string LevelJsonPosition = "D:\\Desktop\\local\\pos.json"; //地图编辑器生成的地图文件的地址}
Q:为什么ip后面还有,A:因为Springboot服务器的http请求需要把写入删除拉取区分。
热更打包,注意把左上角的profile改成自己的(我用的是remote,默认是defaut),给每个包打上标签(更新使用)

热更逻辑:
我们的代码热更方式就是:用Hybrid打出一个热更的dll,然后把dll转存为比特文件,放到Addressable包里,热更到本地后加载新的dll。
启动逻辑:build一个场景,里面放CheckAssetsUpdate 脚本,在所有包体下载完成后,加载包中的StartScene场景。startScene场景里用代码启动游戏启动逻辑。

using HybridCLR;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
using static UnityEngine.Rendering.VirtualTexturing.Debugging;public class CheckAssetsUpdate : MonoBehaviour
{private AsyncOperationHandle<long> downloadHandle;AsyncOperationHandle remote;private StaticLoadingPage loadPage;void Start(){LoadDefDLL();StartCoroutine(CheckUpdate());loadPage=GetComponent<StaticLoadingPage>();}private void LoadDefDLL(){//����dllDebug.Log("Starting to check and download assets with label: all");List<string> aotDllList = new List<string>{"System.Core.dll","System.dll","Unity.Addressables.dll","Unity.ResourceManager.dll","UnityEngine.CoreModule.dll","mscorlib.dll",};foreach (var dllName in aotDllList){byte[] dllBytes = File.ReadAllBytes($"{Application.streamingAssetsPath}/{dllName}");LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(dllBytes, HomologousImageMode.SuperSet);if (err != LoadImageErrorCode.OK){Debug.LogError($"Failed to load AOT DLL: {dllName}, Error: {err}");// If any AOT DLL fails to load, stop the process}else{Debug.Log($"{dllName} 加载成功");}}}private IEnumerator CheckUpdate(){downloadHandle = Addressables.GetDownloadSizeAsync("all");//Debug.Log("加载"+ downloadHandle);yield return downloadHandle;Debug.Log("检查下载资源");if (downloadHandle.Status == AsyncOperationStatus.Succeeded){if (downloadHandle.Result <= 0){Debug.Log("没有更新");EnterGame();}else{Debug.Log("更新游戏");StartCoroutine(Download());}}yield return null;}IEnumerator Download(){remote = Addressables.DownloadDependenciesAsync("all", true);while (!remote.IsDone){var bytes = remote.GetDownloadStatus().DownloadedBytes;var totalBytes = remote.GetDownloadStatus().TotalBytes;var status = remote.GetDownloadStatus();float progress = status.Percent;Debug.Log($"Download progress : {progress}");loadPage.Loading(progress);yield return null;}EnterGame();}void EnterGame(){Debug.Log("加载了:HotUpdate.dll"+ remote);var loadDllAsync = Addressables.LoadAssetAsync<TextAsset>(FrameworkConfig.DLLName);loadDllAsync.Completed += OnHotUpdateDllLoaded;}void OnHotUpdateDllLoaded(AsyncOperationHandle<TextAsset> handle){if (handle.Status == AsyncOperationStatus.Succeeded){Debug.Log("DLL 加载完毕");Assembly hotUpdate = null;try{hotUpdate = Assembly.Load(handle.Result.bytes);Debug.Log("加载游戏");//GameRoot.Instance.Init();AsyncOperationHandle<SceneInstance> lastHandle= Addressables.LoadSceneAsync(FrameworkConfig.StartSceneName, LoadSceneMode.Single);lastHandle.Completed += (o) =>{loadPage.Loading(1);Destroy(loadPage.loadingCanvas.gameObject,2);};}catch (Exception ex){Debug.LogError("DLL加载错误: " + ex.Message);return;}}}
}
报错解决文档
专门记录一些坑,遇到报错问题可以来这里解决:
【有道云笔记】HybridCLR+Addressables热更
https://note.youdao.com/s/2QhPpppU
或者去官网。
源码:
larito/GameClient (客户端)
larito/StaticServer (静态服务器)
相关文章:
HybridCLR+Adressable+Springboot热更
本文章会手把手教大家如何搭建HybridCLRAdressableSpringboot热更。 创作不易,动动发财的小手点个赞。 安装华佗 首先我们按照官网的快速上手指南搭建一个简易的项目: 快速上手 | HybridCLR 注意在热更的代码里添加程序集。把用到的工具放到程序集里…...
电脑连接示波器显示波形
通过网线连接示波器和电脑,将示波器波形显示在电脑上直接复制图片至报告中,以下是配置步骤。 一、设备 网线,Tektronix示波器,电脑 二、使用步骤 1.用网线连接电脑和示波器 2.电脑关掉WiFi,查看IPv4网关地址…...
监听其他音频播放时暂停正在播放的音频
要实现当有其他音频播放时暂停当前音频,你可以使用全局事件总线或 Vuex 来管理音频播放状态。这里我将展示如何使用一个简单的事件总线来实现这个功能。 首先,你需要创建一个事件总线。你可以在项目的一个公共文件中创建它,例如 eventBus.js…...
小熊猫C++安装EasyX最新教程
1.下载EasyX 官网下载: EasyX 官网https://easyx.cn/ 2.将下载文件改格式解压 注意:下载文件为.exe格式,需将其格式改成.zip格式! 如何改格式? a.若文件名字未显示.exe (1).打开此电脑 (2).点击上端的查看 (…...
安装VM和Centos
安装VM 一、打开虚拟机 二、选择典型 三、选择光盘 四、指定虚拟机位置 五、设置磁盘大小并拆分为多个文件 六、完成 安装Centos 一、上述过程完成后我们直接打开虚拟机 二、语言选择中文 三、默认安装位置并点击完成 四、点击开始安装 五、点击设置密码 设置完密码后点击完成…...
git 命令 设置别名
在Git中,您可以通过以下命令查看所有的alias(别名): git config --get-regexp alias 这个命令会列出所有配置的alias,例如: alias.st.status alias.co.checkout alias.br.branch ... 如果您想查看某个特定a…...
React + TypeScript 全栈开发最佳实践
React TypeScript 全栈开发最佳实践 一、环境搭建与项目初始化 node.js和npm的安装请参考我的文章。 1.1 脚手架选择与工程创建 # 使用Vite 5.x创建ReactTS项目(2025年主流方案) npx create-vitelatest my-app --template react-ts cd my-app npm in…...
springboot志同道合交友网站设计与实现(代码+数据库+LW)
摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本志同道合交友网站就是在这样的大环境下诞生,其可以帮助使用者在短时间内处理完毕庞大的数据信…...
防火墙双机热备---VRRP,VGMP,HRP(超详细)
双机热备技术-----VRRP,VGMP,HRP三个组成 注:与路由器VRRP有所不同,路由器是通过控制开销值控制数据包流通方向 防火墙双机热备: 1.主备备份模式 双机热备最大的特点就是防火墙提供了一条专门的备份通道(心…...
MQTT实现智能家居------4、在Linux上运行MQTT
进入主目录,创建一个MQTT文件夹 cd ~ mkdir MQTT 用FileZilla连接开发板,将我发布的压缩包解压以后放进MQTT 安装cmake sudo apt-get install cmake g编译 & 运行 echo sudo apt-get update >> build.sh #向build.sh文件写入内容 chmod…...
VMware建立linux虚拟机
本文适用于初学者,帮助初学者学习如何创建虚拟机,了解在创建过程中各个选项的含义。 环境如下: CentOS版本: CentOS 7.9(2009) 软件: VMware Workstation 17 Pro 17.5.0 build-22583795 1.配…...
大模型文集开篇稿
2023年,我国AI大模型行业规模已达到147亿元人民币(前瞻产业研究院 数据)。AI大模型的行业应用及技术进步能有效提升各行业生产要素的产出效率并提高了数据要素在生产要素组合中的地位。供给方面,当前AI大模型企业主要通过深化通用…...
python pickle模块
pickle 是 Python 的一个标准模块,它实现了基本的二进制协议,用于对象的序列化和反序列化。序列化是指将对象转换为字节流的过程,这样对象就可以被保存到文件中或通过网络传输。反序列化是指将字节流转换回对象的过程。 使用 pickle 序列化对…...
第16届蓝桥杯模拟赛3 python组个人题解
第16届蓝桥杯模拟赛3 python组 思路和答案不保证正确 1.填空 如果一个数 p 是个质数,同时又是整数 a 的约数,则 p 称为 a 的一个质因数。 请问, 2024 的最大的质因数是多少? 因为是填空题,所以直接枚举2023~2 &am…...
企业知识管理战略整合新路径
跨部门知识协同机制 现代企业知识管理的核心挑战在于突破组织孤岛效应,跨部门知识协同机制的构建需依托结构化流程与智能化工具的融合。通过建立标准化知识元数据体系,企业可实现文档分类、版本控制及权限管理的统一规范,其中Baklib作为云端…...
GO 快速升级Go版本
由于底层依赖升级了,那我们也要跟着升,go老版本已经不足满足需求了,必须要将版本升级到1.22.0以上 查看当前Go版本 命令查看go版本 go version [rootlocalhost local]# go version go version go1.21.4 linux/amd64 [rootlocalhost local]# …...
RBAC授权
4 RBAC授权 4.1 什么是RBAC 在Kubernetes中,所有资源对象都是通过API进行操作,他们保存在etcd里。而对etcd的操作我们需要通过访问kube-apiserver来实现,上面的Service Account其实就是APIServer的认证过程,而授权的机制是通过RBA…...
搜广推校招面经三十一
vivo策略算法 一、机器学习中 L1 和 L2 正则化的原理 见【搜广推校招面经二十五】 L1 正则化将某些特征权重置0实现模型简化,而 L2 正则化主要通过平滑权重来实现模型简化。 1.1. 正则化的原理 正则化的核心思想是在损失函数中加入一个惩罚项(Regula…...
【JavaWeb13】了解ES6的核心特性,对于提高JavaScript编程效率有哪些潜在影响?
文章目录 🌍一. ES6 新特性❄️1. ES6 基本介绍❄️2. 基本使用2.1 let 声明变量2.2 const 声明常量/只读变量2.3 解构赋值2.4 模板字符串2.5 对象拓展运算符2.6 箭头函数 🌍二. Promise❄️1. 基本使用❄️2. 如何解决回调地狱问题2.1回调地狱问题2.2 使…...
C++知识整理day9——继承(基类与派生类之间的转换、派生类的默认成员函数、多继承问题)
文章目录 1.继承的概念和定义2.基类与派生类之间的转换3.继承中的作用域4.派生类的默认成员函数5.实现一个不能被继承的类6.继承与友元7.继承与静态成员8.多继承和菱形继承问题8.1 继承分类及菱形继承8.2 虚继承 1.继承的概念和定义 概念: 继承(inheritance)机制是⾯…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
Leetcode 3577. Count the Number of Computer Unlocking Permutations
Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接:3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯,要想要能够将所有的电脑解锁&#x…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...
HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
uniapp 字符包含的相关方法
在uniapp中,如果你想检查一个字符串是否包含另一个子字符串,你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的,但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...
