Unity项目接入xLua的一种流程
1. 导入xlua
首先导入xlua,这个不用多说

2. 编写C#和Lua交互脚本
基础版本,即xlua自带的版本
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System;
using System.IO;[Serializable]
public class Injection
{public string name;public GameObject value;
}/// <summary>
/// XLua的原生版本
/// </summary>
public class LuaBehaviour : MonoBehaviour
{public TextAsset luaScript;public Injection[] injections;/// <summary>/// 虚拟机唯一/// </summary>internal static LuaEnv luaEnv = new LuaEnv();/// <summary>/// 上一次的GC时间/// </summary>internal static float lastGCTime = 0; /// <summary>/// GC间隔/// </summary>internal const float GCInterval = 1f;private Action luaStart;private Action luaUpdate;private Action luaOnDestroy;private LuaTable scriptScopeTable;private void Awake(){SetPackagePath();scriptScopeTable = luaEnv.NewTable();//给scriptScopeTable设置__index元表,使其能够访问全局using (LuaTable meta = luaEnv.NewTable()){meta.Set("__index", luaEnv.Global);scriptScopeTable.SetMetaTable(meta);}scriptScopeTable.Set("self", this);foreach (var injection in injections){scriptScopeTable.Set(injection.name, injection.value);}//执行脚本luaEnv.DoString(luaScript.text, luaScript.name, scriptScopeTable);//获得生命周期绑定,这里直接使用scriptScopeTable,代表是使用这个脚本的全局去设置的Action luaAwake = scriptScopeTable.Get<Action>("Awake");scriptScopeTable.Get("Start", out luaStart);scriptScopeTable.Get("Update", out luaUpdate);scriptScopeTable.Get("OnDestroy", out luaOnDestroy);if (luaAwake != null){luaAwake();}}private void Start(){if (luaStart != null){luaStart();}}private void Update(){if (luaUpdate != null){luaUpdate();}if (Time.time - lastGCTime > GCInterval){luaEnv.Tick();lastGCTime = Time.time;}}private void OnDestroy(){if (luaOnDestroy != null){luaOnDestroy();}scriptScopeTable.Dispose();luaStart = null;luaUpdate = null;luaOnDestroy = null;injections = null;}/// <summary>/// 设置xlua的加载路径/// </summary>private void SetPackagePath(){//在Unity项目的“Assets”文件夹(或指定的Application.dataPath路径)及其所有子目录中,查找名为“LuaScripts”的目录,并返回一个包含这些目录路径的字符串数组foreach (string dir in Directory.GetDirectories(Application.dataPath,"LuaScripts", SearchOption.AllDirectories)){luaEnv.AddLoader(new FileLoader(dir, ".lua"));luaEnv.AddLoader(new FileLoader(dir, ".lua.txt"));}}
}
Loxodon的版本
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;
using System.IO;
using Object = UnityEngine.Object;/// <summary>
/// Loxodon的版本
/// </summary>
[LuaCallCSharp]
public class LoxodonLuaBehaviour : MonoBehaviour
{public ScriptReference script;public VariableArray variables;protected LuaTable scriptEnv;protected LuaTable metatable;protected Action<MonoBehaviour> onAwake;protected Action<MonoBehaviour> onEnable;protected Action<MonoBehaviour> onDisable;protected Action<MonoBehaviour> onUpdate;protected Action<MonoBehaviour> onDestroy;protected Action<MonoBehaviour> onStart;public LuaTable GetMetatable(){return metatable;}protected virtual void Initialize(){var luaEnv = LuaEnvironment.LuaEnv;scriptEnv = luaEnv.NewTable();LuaTable meta = luaEnv.NewTable();meta.Set("__index", luaEnv.Global);scriptEnv.SetMetaTable(meta);meta.Dispose();scriptEnv.Set("target", this);SetPackagePath(luaEnv);string scriptText = (script.Type == ScriptReferenceType.TextAsset)? script.Text.text: string.Format($"require(\"System\");local cls = require(\"{script.FileName}\");return extends(target,cls);");object[] result = luaEnv.DoString(scriptText, string.Format("{0}({1})", "LuaBehaviour", this.name), scriptEnv);if (result.Length != 1 || !(result[0] is LuaTable)){throw new Exception("");}metatable = (LuaTable)result[0]; //这里使用Lua脚本的返回值去设置,即脚本的返回值去绑定生命周期if (variables != null && variables.Variables != null){foreach (var variable in variables.Variables){var name = variable.Name.Trim();if (string.IsNullOrEmpty(name)){continue;}metatable.Set(name, variable.GetValue());}}onAwake = metatable.Get<Action<MonoBehaviour>>("Awake");onEnable = metatable.Get<Action<MonoBehaviour>>("Enable");onDisable = metatable.Get<Action<MonoBehaviour>>("Disable");onStart = metatable.Get<Action<MonoBehaviour>>("Start");onUpdate = metatable.Get<Action<MonoBehaviour>>("Update");onDestroy = metatable.Get<Action<MonoBehaviour>>("Destroy");}protected virtual void Awake(){this.Initialize();if (this.onAwake != null){this.onAwake(this);}}protected virtual void OnEnable(){if (this.onEnable != null){this.onEnable(this);}}protected virtual void OnDisable(){if (this.onDisable != null){this.onDisable(this);}}protected virtual void Start(){if (onStart != null){onStart(this);}}protected virtual void Update(){if (onUpdate != null){onUpdate(this);}}protected virtual void OnDestroy(){if (this.onDestroy != null){this.onDestroy(this);}onDestroy = null;onUpdate = null;onStart = null;onEnable = null;onDisable = null;onAwake = null;if (metatable != null){metatable.Dispose();metatable = null;}if (scriptEnv != null){scriptEnv.Dispose();scriptEnv = null;}}/// <summary>/// 修改lua的loader/// </summary>/// <param name="luaEnv"></param>private void SetPackagePath(LuaEnv luaEnv){//在Unity项目的“Assets”文件夹(或指定的Application.dataPath路径)及其所有子目录中,查找名为“LuaScripts”的目录,并返回一个包含这些目录路径的字符串数组foreach (string dir in Directory.GetDirectories(Application.dataPath,"LuaScripts", SearchOption.AllDirectories)){luaEnv.AddLoader(new FileLoader(dir, ".lua"));luaEnv.AddLoader(new FileLoader(dir, ".lua.txt"));}}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;public class LuaEnvironment
{private static float interval = 2;private static WaitForSecondsRealtime wait;private static LuaEnv luaEnv;//private static IAsyncResult result;public static float Interval{get => interval;set{if (interval <= 0){return;}interval = value;wait = new WaitForSecondsRealtime(interval);}}public static LuaEnv LuaEnv{get{if (luaEnv == null){luaEnv = new LuaEnv();// if (result != null)// result.Cancel();wait = new WaitForSecondsRealtime(interval);//result = Executors.RunOnCoroutine(DoTick());luaEnv.Tick();}return luaEnv;}}public static void Dispose(){// if (result != null)// {// result.Cancel();// result = null;// }if (luaEnv != null){luaEnv.Dispose();luaEnv = null;}wait = null;}private static IEnumerator DoTick(){while (true){yield return wait;try{luaEnv.Tick();}catch (Exception e){Debug.LogError(e);}}}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Object = UnityEngine.Object;public enum ScriptReferenceType
{TextAsset,FileName
}[Serializable]
public class ScriptReference : ISerializationCallbackReceiver
{
#if UNITY_EDITOR[SerializeField]private Object cachedAsset;
#endif[SerializeField]protected TextAsset text;[SerializeField]protected string fileName;[SerializeField]protected ScriptReferenceType type = ScriptReferenceType.TextAsset;public virtual ScriptReferenceType Type => type;public virtual TextAsset Text => text;public virtual string FileName => fileName;public void OnBeforeSerialize(){Clear();}public void OnAfterDeserialize(){Clear();}protected virtual void Clear(){
#if !UNITY_EDITORswitch (type){case ScriptReferenceType.TextAsset:this.fileName = null;break;case ScriptReferenceType.FileName:this.text = null;break;}
#endif}
}
具体区别可以看两种不同的LuaBehaviour生命周期绑定
然后注意这里的lua文件读取路径设置

具体可以看xlua中自定义lua文件加载的一种方式

3.自定义属性面板



4. Lua脚本部分



因为提前设置了Lua文件的读取路径,都在LuaScripts文件夹下
运行


Lua脚本执行了对应的逻辑,将text的值变为了“你好”,同时打印了协程的输出
注意使用前让xlua生成代码

项目链接
相关文章:
Unity项目接入xLua的一种流程
1. 导入xlua 首先导入xlua,这个不用多说 2. 编写C#和Lua交互脚本 基础版本,即xlua自带的版本 using System.Collections; using System.Collections.Generic; using UnityEngine; using XLua; using System; using System.IO;[Serializable] public…...
Deepseek 接入Word处理对话框(隐藏密钥)
硅基流动邀请码:1zNe93Cp 邀请链接:网页链接 亲测deepseek接入word,自由调用对话,看截图有兴趣的复用代码(当然也可以自己向deepseek提问,帮助你完成接入,但是提问逻辑不一样给出的答案是千差万…...
Office/WPS接入DS等多个AI工具,开启办公新模式!
在现代职场中,Office办公套件已成为工作和学习的必备工具,其功能强大但复杂,熟练掌握需要系统的学习。为了简化操作,使每个人都能轻松使用各种功能,市场上涌现出各类办公插件。这些插件不仅提升了用户体验,…...
ximalaya(三) playUriList值解密--webpack
本文主要介绍解密音频播放url参数。 本文仅代表个人理解,如有其他建议可在评论区沟通。 声明 仅仅记录一下自己的学习方法,不作为其他参考、更不作为商业用途。如有侵犯请联系本人删除 目标地址:aHR0cHM6Ly93d3cueGltYWxheWEuY29tL3NvdW5k…...
ASP.NET Core JWT
目录 Session的缺点 JWT(Json Web Token) 优点: 登录流程 JWT的基本使用 生成JWT 解码JWT 用JwtSecurityTokenHandler对JWT解码 注意 Session的缺点 对于分布式集群环境,Session数据保存在服务器内存中就不合适了&#…...
原生redis实现分布式锁
用 原生 Redis(Jedis、Lettuce) 实现分布式锁,可以参考 Redisson 的原理,但需要自己处理锁的自动续期、故障恢复等细节。核心思路是使用 Redis 的 SET NX EX 或 SET PX NX 命令来实现互斥锁,并利用 Lua 脚本 保障原子性…...
光伏-报告显示,假期内,硅料端签单顺序发货相对稳定。若3月份下游存提产,则不排除硅料价格有上调预期。
据TrendForce集邦咨询报告显示,假期内,硅料端按照前期签单顺序发货,相对稳定。若3月份下游存提产,则不排除硅料价格有上调预期。 002306中科云网 旅游 | 公司为提供复合菜系特色餐饮的连锁企业,形成了以粤菜ÿ…...
【信息系统项目管理师-案例真题】2017上半年案例分析答案和详解
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 试题一【问题1】8 分【问题2】4 分【问题3】8 分【问题4】5 分试题二【问题1】10 分【问题2】8 分【问题3】6 分【问题4】5 分试题三【问题1】5 分【问题2】7 分【问题3】6 分【问题4】3 分试题一 阅读下列说明…...
滴水逆向_程序实现弹窗修改OEP
作业: 几个很重要的注意事项。 1 我们模拟的是内核如何将一个文件硬盘中拉伸到内存中,但是我们做的仅仅是 模拟拉伸过程。也就是说其中的属性字段是无差别的拷贝的。 但是加载exe的时候 ,imagebase 是随机分配的。 我们打开内存中的exe&…...
快速上手——.net封装使用DeekSeek-V3 模型
📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,用爱发电,去丈量人心,是否能达到人机合一?开工大吉 新的一年就这么水灵灵的开始了,在这里,祝各位读者新春快乐,万事如意! 新年伊…...
ReactNative进阶(五十九):存量 react-native 项目适配 HarmonyOS NEXT
文章目录 一、前言二、ohos_react_native2.1 Fabric2.2 TurboModule2.2.1 ArkTSTurboModule2.2.2 cxxTurboModule: 三、拓展阅读 一、前言 2024年10月22日19:00,华为在深圳举办“原生鸿蒙之夜暨华为全场景新品发布会”,主题为“星河璀璨&…...
1-2 面向对象编程方法
1.0 面向对象编程思维 在面向对象风格中,结构体被看做数据(data),而操作数据的函数称作方法(method)。目前函数 和数据是分离的,函数并不直接操作数据,我们需要拿到函数返回的结果&a…...
k8s中部署nginx的pod
在当今数字化的浪潮中,容器编排技术成为了构建和管理应用程序的核心力量。Kubernetes(简称 k8s)作为容器编排领域的佼佼者,凭借其强大的自动化部署、扩展和管理能力,深受开发者和运维人员的青睐。而 Nginx 作为一款高性…...
CSS 组合选择符详解与实战示例
在 Web 开发过程中,CSS 用于定义页面元素的样式,而选择器则帮助我们精确定位需要添加样式的元素。今天我们主要来讲解 CSS 中的组合选择符,它们能够根据 DOM 结构中元素之间的关系来选中目标元素,从而写出结构清晰、易于维护的 CS…...
html为<td>添加标注文本
样式说明: /*为td添加相对定位点*/ .td_text {position: relative; }/*为p添加绝对坐标(相对于父元素中的定位点)*/ .td_text p {position: absolute;top: 80%;font-size: 8px; }参考资料:...
apachePoi中XSSFClientAnchor图片坐标简述;填充多张图片
概述 业务中经常会遇到在单元格内填充图片的需求,而且要求指定图片在单元格内的位置。 一般都是用的apache的poi,设置图片坐标。 HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2)dx1 dy1 起始单元…...
无界构建微前端?NO!NO!NO!多系统融合思路!
文章目录 微前端理解1、微前端概念2、微前端特性3、微前端方案a、iframeb、qiankun --> 使用比较复杂 --> 自己写对vite的插件c、micro-app --> 京东开发 --> 对vite支持更拉跨d、EMP 方案--> 必须使用 webpack5 --> 很多人感觉不是微前端 --> 去中心化方…...
数据留痕的方法
在项目中,数据变更时,经常需要记录上次的数据,以便查看对比,专业术语叫做数据留痕。数据变更留痕(即记录数据的变更历史)是一个常见的需求,例如在审计、追踪数据变化或满足合规性要求的场景中。…...
Glustefs 服务端配置流程
Glustefs 服务端配置流程 (一)环境搭建 名称ip硬件设备文件虚拟机 gluster1192.168.101.12G新磁盘/dev/sdb虚拟机 gluster2192.168.101.22G新磁盘/dev/sdb虚拟机 gluster3192.168.101.32G新磁盘/dev/sdb (二)磁盘格式化&#x…...
为飞牛OS基于FRP的内网穿透开启HTTPS加密
前言 玩NAS的朋友应该有比较多只是在家庭局域网使用,比如日常看看电影、备份手机照片什么的,这属于家庭局域网的使用场景。 当然了,如果你经常出差,或者过年回家不想把NAS也背回去,或者是想上班摸鱼,或者是…...
《基于Python与DashScope的智能语音合成工具开发》
《基于Python与DashScope的智能语音合成工具开发》 在当今数字化时代,语音合成技术已经广泛应用于各种场景,如智能语音助手、有声读物、导航系统等。本文将介绍如何使用Python和DashScope平台开发一个简单而功能强大的文字转语音工具。通过这个工具&…...
快速上手Vim的使用
Vim Linux编辑器-vim使用命令行模式下所有选项都可以带数字底行模式可视块模式(ctrlV进入) Linux编辑器-vim使用 Vim有多种模式的编辑器。能帮助我们很快的进行代码的编辑,甚至完成很多其他事情。 默认情况下我们打开vim在命令模式下&#x…...
vue学习第四天 v-on事件绑定
v-on绑定事件如下,点击按钮会弹出alert v-on:事件具体名称“事件调用的函数名” 事件调用的函数写在methods里面 在methods属性的函数里,可以用this获取data的数据,this代表的就是整个vue实例 用this.age就可以拿到age࿰…...
2.8寒假作业
web:[HNCTF 2022 Week1]2048 之前也做过类似的题目,之前的解法是直接get传参score20000,可以尝试 打开环境看源代码,直接改源代码显然是不行的,那么用一下上面的办法也不行,估计是要改其他方向的ÿ…...
PyTorch torch.sign函数介绍
torch.sign 是 PyTorch 库中用于计算输入张量每个元素符号的函数。下面从功能概述、函数原型、参数解释、返回值、使用示例以及与相关函数对比等方面详细介绍 torch.sign。 功能概述 torch.sign 函数会返回一个与输入张量形状相同的新张量,其中每个元素的值表示输…...
Formality:时序变换(五)(寄存器复制)
相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 一、引言 时序变换在Design Compiler的首次综合和增量综合中都可能发生,它们包括:时钟门控(Clock Gating)、寄存器合并(Register Merging)、…...
音频知识基础
音频知识基础 声音属性声音度量人耳特性通道数音频数字化传输接口 声音属性 响度 响度是人耳对声音强弱的主观感受; 主要和声波的振幅相关,同时也和频率有一定关系; 音调 音调是人耳对声音高低的主观感受; 主要与频率相关&#…...
科技赋能数字内容体验的核心技术探索
内容概要 在数字化时代,科技的迅猛发展为我们的生活和工作带来了深刻的变革。数字内容体验已经成为人们获取信息和娱乐的重要途径,而这背后的技术支持则扮演着至关重要的角色。尤其是在人工智能、虚拟现实和区块链等新兴技术的推动下,数字内…...
DeepSeek-R1 本地大模型搭建对接API
DeepSeek-R1 在这里将学到很多知识 欢迎使用使用DeepSeek-R1本地大模型DeepSeek 的模型基础说明DeepSeek的本地 API 说明DeepSeek 本地模型搭建1、执行命令安装及测试 DeepSeek-R1 API接口调用当然,我们为了让用户更加便捷,我们把API 接口全部放到上面截…...
利用NestJS构建高效的RESTful API接口
1. 引言 项目背景与目标 随着互联网应用的快速发展,RESTful API已成为前后端分离架构中的重要组成部分。本文将介绍如何使用NestJS构建一个高效且可维护的RESTful API接口。目标是通过NestJS的模块化和依赖注入特性,实现一个易于扩展和维护的API系统。 RESTful API的重要性…...
