热更新、Xlua中Lua调用C#代码

每日一句:保持须臾的浪漫,理想的喧嚣,平等的热情

什么是冷更新?

开发者将测试好的代码,发布到应用商店的审核平台,平台方会进行稳定性及性能测试。测试成功后,用户即可在AppStore看到应用的更新信息,用户点击应用更新后,需要先关闭应用,再进行更新

什么是热更新?

广义:无需关闭应用,不停机状态下恢复漏洞,更新资源等,重点是更新逻辑代码

狭义定义(ios热更新):无需将代码重新打包提交至AppStore,即可更新客户端的执行代码,即不用下载app 而自动更新程序

现状:苹果禁止了C#的部分反射操作,禁止JIT(即时编译,程序运行时创建并运行新代码),不允许逻辑热更新,只允许使用AssetBundle进行资源热更新

注意:2017年,苹果更新了热更新政策说明,上线后的项目一旦发现使用热更新,一样会以下架处理

为何要热更新?

缩短用户获取新版应用的客户端的流程,改善用户体验,具体到ios平台的应用上,有以下几个原因

AppStore的审核周期难控制

手机应用更新频繁

对于大型应用,更新成本太大

终极目标

不重新下载,不停机状态下完全变换一个应用内容

每个平台如何做热更新?

Android 、PC(C#)

将执行代码预编译为AssemblyDLL

将代码作为TextAsset打包进AssetBundle

运行时调用AssemblyDLL代码

更新相应的AssetBundle即可实现热更新

ios(lua)

苹果官方禁止ios下的程序热更新:JIT在ios下无效

热更新方案:Unity+Lua插件热更新、Xlua中Lua调用C#代码_第1张图片

常见的Unity热更新插件

slua:最快的Lua插件

tolua:由ulua发展而来的,第三代Lua热更新方案

xlua:特性最先进的Lua插件

ILRuntime:纯C#实现的热更新插件

热更新、Xlua中Lua调用C#代码_第2张图片

链接:https://pan.baidu.com/s/1er3OBGur5mA1PdIljfq8FQ?pwd=dpvj

提取码:dpvj

xlua-master分享热更新、Xlua中Lua调用C#代码_第3张图片

解决办法删掉

即可热更新、Xlua中Lua调用C#代码_第4张图片

Xlua中Lua调用C#代码 为什么?

C#实现的系统,因为Lua可以调用,所以完成可以换成Lua实现,因为Lua可以即时更改,即时运行,所以游戏的代码逻辑就可以随时修改

实现和C#相同效果的系统,如何实现?

Lua调用Unity的各种API,从而实现C#开发系统同样的效果

using XLua;

public class First : MonoBehaviour

{

    void Start()

    {

        //lua是解释型语言,所以需要获得lua的解析器

        //xLua解析器获得

        LuaEnv env = new LuaEnv();

        //解析器运行Lua代码,把字符串当成Lua代码执行

        env.DoString("print('Hello world ### !')");

        //解析器释放

        env.Dispose();

    }

}

_______________________________________________________________________

using UnityEngine;

using XLua;

//使用Lua调用C#

public class DoString : MonoBehaviour

{

    void Start()

    {

        LuaCallCSharpCode();

    }

    public void LuaCallCSharpCode()

    {

        LuaEnv env = new LuaEnv();

        //Lua调用C#代码(cs.命名空间.类名.方法名(参数))

        env.DoString("CS.UnityEngine.Debug.Log('from lua')");

        env.Dispose();

    }

}热更新、Xlua中Lua调用C#代码_第5张图片

_______________________________________________________________________

using XLua;

public class Loader : MonoBehaviour

{

    void Start()

    {

        LuaEnv env = new LuaEnv();

        //对应test.lua

        //内置加载器会扫描预制的目录,查找是否存在test.lua

        //xlua存在默认加载器,StreamingAssets目录下可以加载文件中

        env.DoString("require('test')");

        env.Dispose();

    }

}

_______________________________________________________________________

XLua的环境控制

接触一个新的Lua项目时,先要弄懂Lua的加载器规则,只有这样,才能弄懂项目的Lua执行流程

Xlua的单例运行环境

    Xlua解析器创建销毁

    Xlua加载器编写

using System.IO;

using UnityEngine;

using XLua;

public class xLuaEnv

{

    private static xLuaEnv _Instance = null;

    public static xLuaEnv Instance

    {

        get

        {

            if(_Instance==null)

            {

                _Instance = new xLuaEnv();

            }

            return _Instance;

        }

    }

    private LuaEnv _Env;

    //创建单例的时候,Lua运行环境,会一起被创建

    private xLuaEnv()

    {

        _Env = new LuaEnv();

        _Env.AddLoader(_ProjectLoader);

    }

    //创建自定义Lua加载器,这样就可以任意订制项目的Lua脚本的存储位置

    private byte[] _ProjectLoader(ref string filepath)

    {

        string path = Application.dataPath;

        path = path.Substring(0, path.Length - 7) + "/DataPath/Lua/" + filepath + ".Lua";

        //因为"Application.dataPath"在上线的代码中无法获得,所以上线时,需要将Lua的存储路径,

        //指向到"Application.persistentDataPath"

        if(File.Exists(path))

        {

            return File.ReadAllBytes(path);

        }

        else

        {

            return null;

        }

    }

    public void Free()

    {

        //释放LuaEnv,同时也释放单例对象,这样下次调单例对象,会再次产生Lua运行环境

        _Env.Dispose();

        _Instance = null;

    }

    public object[] DoString(string code)

    {

        return _Env.DoString(code);

    }

}

——————————————————————————————————————

静态

public class LuaCallStatic : MonoBehaviour

    {

        void Start()

        {

            xLuaEnv.Instance.DoString("require('C2L/LuaCallStatic')");

        }

        private void OnDestroy()

        {

            xLuaEnv.Instance.Free();

        }

}

LuaCallStatic.lua

print(‘LuaCallStatic’)

using UnityEngine;

namespace HX

{

    public static class TestStatic

    {

        public static int ID = 99;

        public static string Name

        {

            get;

            set;

        }

        public static string Output()

        {

            return "static";

        }

        public static void Default(string str = "abc")

        {

            Debug.Log(str);

        }

    }

    public class LuaCallStatic : MonoBehaviour

    {

        void Start()

        {

            xLuaEnv.Instance.DoString("require('C2L/LuaCallStatic')");

        }

        private void OnDestroy()

        {

            xLuaEnv.Instance.Free();

        }

    }

}

LuaCallStatic.lua

--Lua调用静态类

--规则“cs.命名空间.类名.成员变量"

print(CS.HX.Teststatic.ID)

--给静态属性赋值

 CS.HX.TestStatic.Name="admin"

print(CS.HX.Teststatic.Name)

--静态成员方法调用

--规则"CS.命名空间.类名.方法名()"

print(CS.HX.Teststatic.Output())

--使用默认值

 CS.HX.Teststatic.Default()

--使用Lua传递的值

 CS.HX.Teststatic.Default("def")

_______________________________________________________________________________________________

public class NPC

{

    public string Name;

    public int HP

    {

        get;

        set;

    }

    public NPC()

    {

    }

    public NPC(string name)

    {

        Name = name;

    }

}

public class LuaCallObject : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallObject')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallObject.lua

--在当前表中调用表里变量

--Lua实例化类

--C#NPC obj=new NPC()

--通过调用构造函数创建对象

local obj=CS.NPC()

obj.HP=100

print(obj.HP)

local obj1=CS.NPC("admin")

print(obj1.Name)

--表方法希望调用表成员变量(表:函数())

--为什么是冒号,对象引用成员变量时,会隐性调用this,等同于Lua中的self

--Lua实例化GameObject

CS.UnityEngine.GameObject("LuaCreateGo")

local go=CS.UnityEngine.GameObject("LuaCreateGo")

go:AddComponent(typeof(CS.UnityEngine.BoxCollider))

结构体

public struct TestStruct

{

    public string Name;

    public string Output()

    {

        return Name;

    }

}

public class LuaCallStruct : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallStruct')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallStruct.lua

--结构体

--和对象调用保持一致

local obj=CS.TestStruct()

obj.Name="admin"

print(obj.Name)

print(obj:Output())

枚举

using UnityEngine;

public enum TestEnum

{

    LOL=0,

    Data2

}

public class LuaCallEnum : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallEnum')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallEnum.lua

--C# TestEnum.LoL

--CS.命名空间.枚举名.枚举值

--枚举获得是userdata自定义数据类型,获得其他语言数据类型时,就是userdata

print(type(CS.TestEnum.LOL))

print(CS.TestEnum.Data2)

--转换获得枚举值

print(CS.TestEnum._CastFrom(0))

print(CS.TestEnum._CastFrom("Data2"))

重载函数

public class TestOverload

{

    public static void Test(int id)

    {

        Debug.Log("数字类型:" + id);

    }

    public static void Test(string name)

    {

        Debug.Log("字符串类型:" + name);

    }

    public static void Test(int id,string name)

    {

        Debug.Log("两个数值:"+id+","+name);

    }

}

public class LuaCallOverload : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallOverload')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallOverload.lua

--重载函数

--数字重载函数

CS.TestOverload.test(99)

CS.TestOverload.test("admin")

--不同参数的重载函数

CS.TestOverload.test(100,"root")

重写、继承

public class Father

{

    public string Name = "father";

    public void Talk()

    {

        Debug.Log("这是父类中的方法");

    }

    public virtual void Override()

    {

        Debug.Log("这是父类中的虚方法");

    }

}

public class Child:Father

{

    public override void Override()

    {

        Debug.Log("这是子类中重写方法");

    }

}

public class LuaCallBase : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallBase')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallBase.lua

--调用Father

local father=CS.Father()

print(father.Name)

father:Override()

--调用Child

local child=CS.Child()

print(child.Name)

child:Talk()

child:Override()

类扩展

public class TestExtend

{

    public void Output()

    {

        Debug.Log("类本身带的方法");

    }

}

//类扩展,需要给扩展方法编写的静态类添加LuaCallCSharp,

//否则Lua无法调用到

[LuaCallCSharp]

public static class MyExtend

{

    public static void Show(this TestExtend obj)

    {

        Debug.Log("类扩展实现的方法");

    }

}

public class LuaCallExtend : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallExtend')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallExtend.lua

local obj=CS.TestExtend()

obj:Output()

obj:SHow()

委托

using UnityEngine;

public delegate void DelegateLua();

public class TestDelegate

{

    public static DelegateLua Static;

    public DelegateLua Dynamic;

    public static void StaticFunc()

    {

        Debug.Log("C#静态成员函数");

    }

}

public class LuaCallDelegate : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallDelegate')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallDelegate.lua

--委托

--C#给委托赋值

--TestDelegate.Static=TestDelegate.StaticFunc

--TestDelegate.Static+=TestDelegate.StaticFunc

--TestDelegate.Static-=TestDelegate.StaticFunc

CS.TestDelegate.Static=CS.TestDelegate.StaticFunc

CS.TestDelegate.Static()

--Lua中如果添加了函数到静态委托变量中后,委托不再使用后,记得释放

CS.TestDelegate.Static=nil

local func=function ()

    print(":这是Lua函数")

end

--覆盖添加委托

CS.TestDelegate.Static=func

CS.TestDelegate.Static=CS.TestDelegate.Static+func

CS.TestDelegate.Static=CS.TestDelegate.Static-func  

--调用以前应确定委托有值

if(CS.TestDelegate.Static~=nil)

then

    CS.TestDelegate.Static()

end

CS.TestDelegate.Static=nil

--根据委托判定赋值方法

if(CS.TestDelegate.Static==nil)

then

    CS.TestDelegate.Static=func

else

    CS.TestDelegate.Static=CS.TestDelegate.Static+func

end

local obj=CS.TestDelegate()

obj.Dynamic=func

obj.Dynamic()

obj.Dynamic=nil

事件

public delegate void EventLua();

public class TestEvent

{

    public static event EventLua Static;

    public static void StaticFunc()

    {

        Debug.Log("这是静态函数");

    }

    public static void CallStatic()

    {

        if(Static!=null)

        {

            Static();

        }

    }

    public event EventLua Dynamic;

    public void CallDynamic()

    {

        if(Dynamic!=null)

        {

            Dynamic();

        }

    }

}

public class LuaCallEvnet : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallEvnet')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

LuaCallEvnet.lua

--Lua添加事件

CS.TestEvent.Static("+",CS.TestEvent.StaticFunc)

CS.TestEvent.CallStatic()

CS.TestEvent.Static("-",CS.TestEvent.StaticFunc)

--添加动态成员变量

local func=function ()

    print("来自于Lua的回调函数")

end

local obj=CS.TestEvent()

obj:Dynamic("+",func)

obj:CallDynamic()

obj:Dynamic("-",func)

--xlua实现了typeof关键字,所以可以用类型API替代Unity内置的泛型方法

public class LuaCallGenericType : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallGenericType')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

public class TestGenercType

{

    public void Output<T>(T data)

    {

        Debug.Log("泛型方法:" + data.ToString());

    }

    public void Output(float data)

    {

        Output<float>(data);

    }

    public void Output(string data)

    {

        Output<string>(data);

    }

}

LuaCallGenericType.lua

local obj=CS.TestGenericType()

obj:Output(99)  

obj.Output("admin")

local go=CS.UnityEngine.GameObject("LuaCreate")

go:AddComponent(typeof(CS.UnityEngine.BoxCollider))

多返回值

public class LuaCallOutRef : MonoBehaviour

{

    void Start()

    {

        xLuaEnv.Instance.DoString("require('C2L/LuaCallOutRef')");

    }

    private void OnDestroy()

    {

        xLuaEnv.Instance.Free();

    }

}

public class TestOutRef

{

    public static string Func1()

    {

        return "Func1";

    }

    public static string Func2(string str1,out string str2)

    {

        str2 = "Func2 out";

        return "Func2";

    }

    public static string Func3(string str1, ref string str2)

    {

        str2 = "Func3 Ref";

        return "Func3";

    }

    public static string Func4(ref string str1,string str2)

    {

        str1 = "Func4 Ref";

        return "Func4";

    }

}

LuaCallOutRef.lua

local r1=CS.TestOutRef.Func1()

print(r1)

--C# out返回的变量,会赋值给Lua的第二个接受返回值变量

local out2

local r2,out1=CS.TestOutRef.Func2("admin",out2)

print(r2,out1,out2)

--C# ref返回的变量,会赋值给Lua的第二个接受返回值变量

local ref2

local r3,ref1=CS.TestOutRef.Func3("root",ref2)

print(r3,ref1,ref2)

--即使out ref 作为第一个参数,其结果依然会以Lua的多个返回值进行返回

local ref4

local r4,ref3=CS.TestOutRef.Func4(ref4,"test")

print(r4,ref3,ref4)

你可能感兴趣的:(UNITY,lua,c#,开发语言)