C# 实现 rtc_通过Xlua实现unity热更新的一个小例子

通过Xlua实现unity热更新的一个小例子

一.介绍

热更新是指在更新游戏资源或者逻辑的时候不需要开发者将游戏再打包、发布、玩家重新下载安装包,而是可以通过将需要更新的资源打包成AssetBundle文件发布到服务器,然后游戏程序通过下载服务器的AssetBundle替换本地文件来达到游戏更新的流程。

​ 打包出来的unity制作的游戏,如果在代码(代码用的是c#语言)上有需要更改的地方,必须重新打包,因为c#语言需要重新编译为dll文件,而如果是lua语言编写,则不需要重新编译。

​ 如果想让lua和c#之间互相调用,可以借用一些开源的Lua插件,比如xLua,toLua。在例子中使用的是xLua插件

二.准备工作

1.xLua

xLua下载方式:https://github.com/Tencent/xLua/releases

下载xlua_v2.1.14.zip

72916a84f39ca86bd4701339df216db5.png

867ab0cdb0d8bf17af0c5d41f129a565.png

将Tools文件夹复制到工程项目,与Assets同级

3489cb9015becbe56fbe769628dde432.png

将Assets文件夹中的文件复制到工程项目的Assets文件夹里

2.将自己的电脑变成一个本地的服务器

打开控制面板-选择管理工具-IIS-在网站处右键添加网站-填写相关项-启动新建的网站

0f65b5f60230e009f1d8c3fb04179c32.png

3fec5ef987f74d771e68c3fcd7e38745.png

9496237e7bcabb52d2c5cf1ff61b9842.png

其中应用程序池要选择DefaultAppPool,物理路径为你希望服务器所在的路径,端口可以填一个二位数字

1266ae440bcc0ac33a2606ac91fa65ec.png

设置完成后,在浏览器中搜索localhost:端口即可查看服务器存放的文件

b43c40ce8e7177c0ffbf1e55b700381f.png

3.安装执行Lua的IDE

下载地址:https://www.runoob.com/lua/lua-environment.html

4.在unity中加入HOTFIX_ENABLE标签

选择Edit->Project Setting->Player 右边Inspector列表中

525a44d7e42202bedb2fd6ad32419c19.png

三.打包AssetBundle

1.将需要打包成AB文件的资源添加AssetBundle标签

37ef9b4eddef0c71d590e16c45e5a296.png

其中,要打在同一个AB包的资源,标签要求一致

2.编写打包代码

using UnityEditor;
using System.IO;

public class CreateAssetBundles
{
    [MenuItem("Assets/BuildAssetBundles")]
    static void BuildAllAssetBundles()
    {
        //要写两个'/',一个是转义符,
        string dir = "F://Web Server//AssetBundles";
        if (Directory.Exists(dir) == false)
        {
            Directory.CreateDirectory(dir);
        }
        //参数 打包路径,压缩方式,打包平台
        BuildPipeline.BuildAssetBundles(dir, BuildAssetBundleOptions.None, BuildTarget.StandaloneWindows64);
    }
}

这里我服务器的路径为F:Web Server

上述脚本可在Editor模式下运行,不需要挂在GameObject上

9f4706b8b6ff6cf5c7a17a56e7897958.png

点击BuildAssetBundles即可将需要打包成AB文件的资源上传到服务器

d4e943210abd4bc08f8e0533aa76340e.png

4bbfb7d35409a6cd610e3b8664258ff8.png

四.热更新

给步骤三中的cube添加一个用来测试热更新的脚本,这个脚本会在游戏时让cube的scale扩大到原来的2倍,rotation的x,y,z都增加30。类上方添加特性Hotfix使其可热更新。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

[Hotfix]
public class ChangeSelf : MonoBehaviour
{
    public Vector3 currentScale;

    public Quaternion currentRotation;

    public Vector3 laterScale;

    public Quaternion laterRotation;
    // Start is called before the first frame update
    void Start()
    {
        currentScale = this.transform.localScale;
        currentRotation = this.transform.localRotation;
        ChangeScale(currentScale);
        ChangeRotation(currentRotation);
        this.transform.localScale = laterScale;
        this.transform.localRotation = laterRotation;
    }

    public void ChangeScale(Vector3 scale)
    {
        laterScale = scale * 2;
        //this.transform.localScale = laterScale;
    }

    public void ChangeRotation(Quaternion rotation)
    {
        laterRotation = Quaternion.Euler(rotation.eulerAngles.x+30, rotation.eulerAngles.y+30, rotation.eulerAngles.z+30);
        //this.transform.localRotation = laterRotation;
    }
}

在服务器中添加热更新的lua脚本,路径:

bdb494568abd86aca3aaecd69f204941.png

代码:

--hotfix中的参数分别为要进行热更新的类,要更新的方法,方法所在的类(function中的第一个参数指方法所在的类,其他参数为要更新的方法的参数)
xlua.hotfix(CS.ChangeSelf,'ChangeScale',function(self,scale)
self.laterScale = scale * 0.5
end
)
local Quaternion = CS.UnityEngine.Quaternion
local rot = CS.UnityEngine.Quaternion() --新建一个对象
xlua.hotfix(CS.ChangeSelf,'ChangeRotation',function(self,rotation)
self.laterRotation = Quaternion.Euler(rotation.eulerAngles.x+60,rotation.eulerAngles.y+60,rotation.eulerAngles.z+60)
end
)

注意:在SciTE中编写完lua脚本,保存的后缀是lua,如果要被unity识别,需要增加txt的后缀

上述的热更新旨在让cube的scale缩小到原来的一半,rotation的x,y,z都增加60

五.加载

1.加载AssetBundle

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;

public class LoadAssetBundles : MonoBehaviour
{
    // Start is called before the first frame update
    IEnumerator Start()
    {
        //这里的地址是服务器端的地址 localhost:后的数字是端口
        string url = @"http://localhost:81/AssetBundles/luatestcube.unity3d";

        while (Caching.ready == false)
        {
            yield return null;
        }
        using (var www = WWW.LoadFromCacheOrDownload(@"http://localhost:81/AssetBundles/luatestcube.unity3d", 2))
        {
            yield return www;
            if (!string.IsNullOrEmpty(www.error))
            {
                Debug.Log(www.error);
                yield return null;
            }
            var assetBundle = www.assetBundle;

            //var asset = assetBundle.mainAsset;
            GameObject cubePrefab = assetBundle.LoadAsset<GameObject>("luatestcube");
            Instantiate(cubePrefab);
        }  
    }  
}

该脚本可挂在空物体上

03ab387b1ff71d693c72548663560ab5.png

2.加载lua脚本

using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using XLua;

public class HotFixTests : MonoBehaviour
{
    private LuaEnv m_kLuaEnv;

    // Start is called before the first frame update
    void Start()
    {
        //xlua虚拟机
        m_kLuaEnv = new LuaEnv();    
        
        //查找指定路径下lua热更新文件
        string path = Application.persistentDataPath + "/ChangeSelf.lua.txt";
        //用协程下载读取文件内容
        StartCoroutine(DownloadFile(path));
    }

    public IEnumerator DownloadFile(string path)
    {
        WWW www = new WWW(path);
        yield return www;
        if (www.isDone)
        {
            System.IO.StreamReader sr = new System.IO.StreamReader(path, Encoding.UTF8);
            if (sr != null)
            {
                //执行lua中的语句
                m_kLuaEnv.DoString(sr.ReadToEnd());
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

public class WWWTexts : MonoBehaviour
{
    private string urlPath = @"http://localhost:81/Xlua/ChangeSelf.lua.txt";//资源网络路径

    private string file_SaveUrl;//资源保存路径

    private FileInfo file;
    // Start is called before the first frame update
    void Start()
    {
        file_SaveUrl = Application.persistentDataPath + "/ChangeSelf.lua.txt";
        file = new FileInfo(file_SaveUrl);

        StartCoroutine(DownFile(urlPath));
    }

    IEnumerator DownFile(string url)
    {
        WWW www = new WWW(url);
        yield return www;
        if (www.isDone)
        {
            Debug.Log("下载完成");

            byte[] bytes = www.bytes;
            CreatFile(bytes);
        }
    }
    
    /// <summary>
    /// 创建文件
    /// </summary>
    /// <param name="bytes"></param>
    void CreatFile(byte[] bytes)
    {
        //将服务器的文件按字节写入保存路径所在文件
        
        Stream stream;
        stream = file.Create();
        stream.Write(bytes, 0, bytes.Length);
        stream.Close();
        stream.Dispose();
    }

}

这两个脚本挂在同一个空物体上

27c9eb74d460dd03858541a3bbab40bd.png

3.运行

每次修改完c#脚本或者lua脚本后,都要先点击第一个,再点击第三个,然后才能运行。

699cb0ec28dcc7b503f0b1de27420f29.png

如果成功执行会输出一下两条日志

54c0c3dc7bdb72f4a1f6aa6474a2de67.png

然后就能运行unity了,运行后发现cube的scale和rotation都实现了lua脚本中的更改,而不是c#脚本中的更改。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
`timerfd` 是 Linux 内核提供的一种定时器机制,可以用于在用户空间中创建定时器。当定时器超时时,内核会向相应的文件描述符写入数据,从而通知用户空间程序。下面简要介绍一下 `timerfd` 的实现原理: `timerfd` 实际上是通过创建一个文件描述符,然后使用 `timer_create` 系统调用创建一个内核定时器来实现的。该系统调用的参数包括定时器的类型、超时时间、定时器的回调函数等等。当定时器超时时,内核会向文件描述符写入数据,用户空间程序可以通过 `read` 系统调用来读取这些数据,从而得知定时器已经超时。 `rtc_alarm` 是 Linux 内核中的另一种定时器机制,它可以用于在硬件级别上触发定时器事件。具体来说,它是通过设置硬件时钟中的闹钟时间来实现定时器功能的。当闹钟时间到达时,硬件时钟会触发一个中断信号,内核会在中断处理函数中执行相应的操作。 `rtc_alarm` 与 `timerfd` 的主要区别在于实现方式不同。`rtc_alarm` 是由硬件时钟实现的,因此可以在系统处于低功耗模式时正常工作;而 `timerfd` 则是由内核软件实现的,需要系统处于运行状态才能正常工作。另外,`rtc_alarm` 通常用于实现系统级别的定时器功能,例如唤醒系统、执行定时任务等等;而 `timerfd` 主要用于应用程序级别的定时器功能,例如定时发送数据、定时执行任务等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值