xLua学习

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


什么是热更新
		广义:无需关闭应用,不停机状态下修复漏洞,更新资源等,重点是更新逻辑代码。
		狭义定义( iOS热更新):无需将代码重新打包提交至AppStore,即可更新客户端
		的执行代码,即不用下载app而自动更新程序。
		现状:苹果禁止了C#的部分反射操作,禁止JIT(即时编译,程序运行时创建并运
		行新代码),不允许逻辑热更新,只允许使用AssetBundle进行资源热更新。


为何要热更新
		缩短用户获取新版应用的客户端的流程,改善用户体验
		具体到iOS平台的应用上,有以下几个原因
			AppStore的审核周期难控制
			手机应用更新频繁
			对于大型应用,更新成本太大
		终极目标
			不重新下载、不停机状态下完全变换一个应用的内容


每个平台如何做热更新
		Android,PC(C#)
			将执行代码预编译为AssemblyDLL
			将代码作为TextAsset打包进AssetBundle
			运行时调用AssemblyDLL代码
			更新相应的AssetBundle即可实现热更新
		iOS(Lua)
			苹果官方禁止iOS下的程序热更新;JIT在iOS下无效
			热更新方案:Unity + Lua插件


常见的Unity热更新插件
		sLua:最快的Lua插件
		toLua:由uLua发展而来的,第三代Lua热更新方案
		xLua:特性最先进的Lua插件
		ILRuntime:纯C#实现的热更新插件

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



xLua中Lua调用C#代码。
为什么?
C#实现的系统,因为Lua可以调用,所以完全可以换成Lua实现,因为Lua可。
以即时更改,即时运行,所以游戏的代码逻辑就可以随时修改。。
实现和C#相同效果的系统,如何实现?。
Lua调用Unity的各种API,从而实现C#开发系统同样的效果,

xLua中C#调用Lua代码。
为什么?
Unity是基于C#语言开发的,所有生命周期函数都是基于C#实现,xLua 本身。
是不存在Unity的相关生命周期函数的。如果希望xLua能够拥有生命周期函。
数,那么我们可以实现C#作为Unity原始调用,再使用C#调用Lua对应的方。
法。|
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;//使用xlua的命名空间
public class First : MonoBehaviour
{
    private void Start()
    {
        //lua时解释型语言,所以 需要获得Lua的解析器
        //xlua解析器获得
        LuaEnv env=new LuaEnv();
        
        //解析器运行lua代码,把字符串当成lua代码去执行
        env.DoString("print('HelloWorld')");

        //解析器释放
        env.Dispose();
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

public class Dostring : MonoBehaviour
{
    private void Start()
    {
        //LuaCallCSharpCode();
        LuaReturnData();
    }

    //使用Lua调用c#代码
    public void LuaCallCSharpCode()
    {
        LuaEnv env=new LuaEnv();
        //lua调用c#代码(CS.命名空间.类名.方法名(参数))
        env.DoString("CS.UnityEngine.Debug.Log('from lua')");
        env.Dispose();
    }

    //Lua返回值给c#
    public void LuaReturnData()
    {
        LuaEnv env=new LuaEnv();
        object[] data = env.DoString("return 100,true");
        Debug.Log("Lua的第一个返回值:"+data[0].ToString());
        Debug.Log("Lua的第一个返回值:"+data[1].ToString());
        env.Dispose();
    }
    
}
using System;-----------------------------自定义解析器-------------------------------
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using XLua;
//Lua是脚本语言,编写代码最重要的方式
//加载器:因为Lua是多脚本编写方式,所以经常会使用require(“文件名”),加载子文件
//加载器是xlua实现了一种方式,可以由c#控制require进行加载
public class Loader : MonoBehaviour
{ 
    private void Start()
    {
        MyLoader();
    }

    
    //系统内置的加载器会在require()命令调用时加载一些特定的目录下的Lua文件
    //Resources目录下
    //StreamingAssets目录下
    public void SystemLoader()
    {
        LuaEnv env=new LuaEnv();
        //对应test.lua
        //内置加载器会扫描预制的目录,查找是否存在
        //xLua存在默认加载器,StereamingAssets目录下可以加载文件,特殊目录,只读目录
        env.DoString("require('test')");
        env.Dispose();
    }

    public void MyLoader()
    {
        //实现xLua解析器
        LuaEnv env=new LuaEnv();
        //将我需要控制require添加到下xLua的回调函数中
        env.AddLoader(ProjectLoader);
        //当Lua中 任意位置执行了require命令,自定义加载器就会执行
        env.DoString("require('test1')");
        env.Dispose();
    } 

    //自定义加载器
    //自定义加载器会先于系统内置加载器执行,当自定义加载器加载到文件后,后续的加载器则不会执行
    //当Lua代码执行require函数时,自定义加载器会尝试获得文件的内容
    //参数,被加载Lua文件的路径
    //如果需要加载的文件不存在,记得返回null
    public byte[] ProjectLoader(ref string filepath)
    {
        //filepath 来自于Lua中的require(”文件名“)
        //构造路径,才能将require加载的文件放到我们想放Lua的文件下去
        //路径可以任意定制(可以将Lua代码放入AB包)
        //因为Application.dataPath在上线的代码中无法获得,所以上线时,
        //需要把Lua的存储路径指向到Application.dataPath
        string path = Application.dataPath;
        path = path.Substring(0, path.Length - 6) +
               "DataPath/Lua/" + filepath+".lua";
        //将Lua文件读取成为字节数组
        //xLua的解析环境会执行我们自定义加载器返回的Lua代码
        if (File.Exists(path))
        {
            return File.ReadAllBytes(path);
        }
        return null;
    }
}
----------------------------工具类---------------------------
using System.IO;
using UnityEngine;
using UnityEngine.UIElements;
using XLua;



    public class xLuaEnv
    {
        #region SingleTon
        private static xLuaEnv _Instance;
        public static xLuaEnv Instance
        {
            get
            {
                if (_Instance==null)
                {
                    _Instance=new xLuaEnv();
                }

                return _Instance;
            }
        }
        #endregion

        #region CreateLuaEnv

        private LuaEnv _env;
        private xLuaEnv()
        {
            _env=new LuaEnv();
            _env.AddLoader(_ProjectLoader);
        }

        #endregion
    
        #region Loader
        private byte[] _ProjectLoader(ref string filepath)
        {
            string path = Application.dataPath;
            path = path.Substring(0, path.Length - 6) +
                   "DataPath/Lua/" + filepath+".lua";
            if (File.Exists(path))
            {
                
                
                return File.ReadAllBytes(path);
            }
            return null;
        }
        
        #endregion

        #region FreeLuaEnv
        public void Free()
        {
            _env.Dispose();
            _Instance = null;
        }
        #endregion

        #region RunLua

        public object[] DoString(string code)
        {
            return _env.DoString(code);
        }
        
        #endregion
        
        //返回Lua环境的全局变量
        public LuaTable Global
        {
            get
            {
                return _env.Global;
            }
        }
    }
-------------------Lua调用c#静态类-------------
using UnityEngine;

    namespace  HX
    {
        public static class TestStatic
        {
            public static int ID = 99;

            public static string Name
            {
                set;
                get;
            }

            public static string Output()
            {
                return "static";
            }

            public static void Default(string str = "abc")
            {
                Debug.Log(str);
            }
        }
    }


    namespace C2L
    {
        public class LuaCallStatic : MonoBehaviour
        {
            private void Start()
            {
                xLuaEnv.Instance.DoString("require('C2L/LuaCallStatic')");
            }

            private void OnDestroy()
            {
                xLuaEnv.Instance.Free();
            }
        }
    }








--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")
-----------------Lua调用c#对象
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class Npc
{
    public string Name;

    public int HP
    {
        get;
        set;
    }
    public Npc()
    {
        
    }

    public Npc(string name)
    {
        Name = name;
    }

    public string Output()
    {
        return Name;
    }
}

public class LuaCallObject : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallObject')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}










--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
--成员方法调用的时候才会用冒号
print(obj1:Output())

--Lua实例化GameObject
--c# GameObject obj=new GameObject('LuaCreateGo')
local go =  CS.UnityEngine.GameObject('LuaCreateGo')
go:AddComponent(typeof(CS.UnityEngine.BoxCollider))










---------------------------Lua调用c#结构体
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public struct TestStruct
{
    public string Name;

    public string Output()
    {
        return Name;
    }
}

public class LuaCallStruct : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallStruct')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}
















--创建结构体的实例 和对象调用保持一致
local obj = CS.TestStruct()

obj.Name="admin"

print(obj.Name)
print(obj:Output())
---------------Lua 调用 c#重载

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

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
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallOverload')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}

















--数字重载函数
CS.TestOverload.Test(99)
--字符串重载函数
CS.TestOverload.Test("admin")
--字符串重建多种类型
CS.TestOverload.Test(88,"admin")
-------------------------Lua调用c#重写

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

public class Father
{
    public string Name = "father";

    public void Talk()
    {
        Debug.Log("这是父类中的方法");
    }
    public virtual void Overide()
    {
        Debug.Log("这是父类中的虚方法");
    }
    
}

public class Child : Father
{
    public override void Overide()
    {
        Debug.Log("这是子类中的重写方法");
    }
}
public class LuaCallBase : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallBase')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}

















--调用Father
local father = CS.Father()
print(father.Name)

father:Overide()


--调用child
local child = CS.Child()
print(child.Name)

child:Talk()
child:Overide()
--------------------------Lua 调用c#枚举

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

public enum TestEnum
{
    LoL=0,
    Dota2
}
public class LuaCallEnum : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallEnum')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}









--c#调用枚举 TestEnum.LOL
--CS.命名空间.枚举名.枚举值
--枚举返回的是userdata自定义的数据类型,
--获得其他语言数据类型时,就是userdata
print(type(CS.TestEnum.LoL))
print(CS.TestEnum.Dota2)

--转换获得枚举值
print(CS.TestEnum.__CastFrom(0))
print(CS.TestEnum.__CastFrom('Dota2'))
---------------------------Lua 调用 c#扩展类
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;

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
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallExtend')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}











--获取对象
local obj = CS.TestExtend()

obj:Output() 
obj:Show()


---------------------------Lua调用c#委托

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

[CSharpCallLua]
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
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallDelegate')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}













--c#给委托赋值
--TestDelegate.Static=TestDelegate.StaticFunc
--TestDelegate.Static+=TestDelegate.StaticFunc
--TestDelegate.Static-=TestDelegate.StaticFunc
--TestDelegate.Static()

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
--调用以前应确定委托有值
CS.TestDelegate.Static()
CS.TestDelegate.Static=nil


--调用前判定
--if(CS.TestDelegate.Static~=nil)
--then
--	CS.TestDelegate.Static()
--end



--根据委托判定赋值方法
--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

-----------------------------Lua调用c#事件

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

public delegate void EventLua();

public class TestEvent
{
    public static void StaticFunc()
    {
        Debug.Log("这是静态函数");
    }
    
    [CSharpCallLua]
    public static event EventLua Static;
    public static void CallStatic()
    {
        if (Static!=null)
        {
            Static();
        }
    }

    
    public event EventLua Dynamic;
    public  void CallDynamic()
    {
        if (Dynamic!=null)
        {
            Dynamic();
        }
    }
    
}

public class LuaCallEvent : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallEvent')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}











--c#添加事件 TestEvent.Static+=TestEvent.StaticFunc

--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)
----------------------------Lua调用c#泛型
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TestGenericType
{
    public void Output(T data)
    {
        Debug.Log("泛型方法:"+data.ToString());
    }
    public void Output(float data)
    {
        Output(data);
    }
    public void Output(string data)
    {
        Output(data);
    }
}

public class LuaCallGenericType : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallGenericType')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}














local obj = CS.TestGenericType()

obj:Output(99)
obj:Output("admin")


local go = CS.UnityEngine.GameObject("LuaCreat")
--xLua实现了typeof关键字,所以可以用类型API代替泛型
go:AddComponent(typeof(CS.UnityEngine.BoxCollider))
------------------------Lua调用c#输入输出参数

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


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";
    }
    
}
public class LuaCallOutRef : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("require('C2L/LuaCallOutRef')");
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}



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)

-------------------Lua将变量反射给c#

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

public class CsharpCallVariable : MonoBehaviour
{
    private void Start()
    { 
        xLuaEnv.Instance.DoString("return require('L2C/CsharpCallVariable')");
        //Lua Env中提供了一个成员变量Global, 它可以用于c#获取Lua的全局变量
        //Global的数据类型是c#实现的LuaTable,LuaTable是xLua实现的c#和Lua中表对应的数据结构
        //xLua会将Lua中的全局变量以Table的方式全部存储在Global中
        
        
        //通过运行环境,导出全局变量,类型是LuaTable
        //LuaTable是c#的数据对象,用于和Lua中的全局变量存储的table对应
        LuaTable g = xLuaEnv.Instance.Global;
        //从Lua中将全局变量提取出来
        //参数:Lua中全局变量的名称
        //类型:Lua中全局变量的名称对应的类型
        //返回值:变量的值
        int num = g.Get("num");
        float rate = g.Get("rate");
        bool isWoman = g.Get("isWoman");
        string name = g.Get("name");
        
        Debug.Log(num);
        Debug.Log(rate);
        Debug.Log(isWoman);
        Debug.Log(name);
    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}








--隐性做了{num=100, rate=99.9, isWoman=false, name="admin"}

num=100

rate=99.9

isWoman=false

name="admin"
----------------------Lua将函数反射给c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XLua;


public delegate void Func1();
public delegate void Func2(string name);
public delegate string Func3();

[CSharpCallLua]
public delegate void Func4(out string name,out int id);

public class CsharpCallFunction : MonoBehaviour
{
    private void Start()
    { 
        xLuaEnv.Instance.DoString("return require('L2C/CsharpCallFunction')");
        
        LuaTable g = xLuaEnv.Instance.Global;
        
        //Lua的函数,会导出为c#的委托类型
        Func1 func1= g.Get("func1");
        func1();
        
        //向Lua中传递函数数据
        Func2 func2= g.Get("func2");
        func2("admin");
        
        //接受Lua函数的返回值
        Func3 func3= g.Get("func3");
        Debug.Log(func3()+",被c#打印");
        
        //Lua多返回值
         Func4 func4= g.Get("func4");
         string name;
         int id;
         func4(out name, out id);
         Debug.Log(name+","+id);
        

    }

    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}











func1=function()
	print("这是Lua中的func1")
end


func2=function(name)
	print("这是Lua中的func2,参数是:"..name)
end


func3=function()
	return "这是Lua中的func3"
end


func4=function()
	return "这是Lua中的func4",88
end
----------------------Lua将元表,结构体反射给c#

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


public delegate void OneStringParams(string name);
public delegate void TransSelf(LuaTable table);
//针对结构体后写的
public delegate string OneStringReturn();
[CSharpCallLua]
public delegate void TransMy(LuaCore table);

//Lua的Table导出到c#的结构体,可以实现c#运行时无GC
[GCOptimize]
public struct LuaCore
{
    public int ID;
    public string Name;
    public bool IsWoman;

    public OneStringParams Func1;
    public OneStringReturn Func2;
    public TransMy Func3;
    public TransMy Func4;
}
public class CsharpCallTable : MonoBehaviour
{
    private void Start()
    {
        xLuaEnv.Instance.DoString("return require('L2C/CsharpCallTable')");
        UseLuaStruct();
        UseLuaTable();
    }

    public void UseLuaTable()
    {
        LuaTable g = xLuaEnv.Instance.Global;
        
        //获取全局变量Core,因为他在Lua中是表,所以取出来是LuaTable
        LuaTable core = g.Get("Core");
        
        //获取Name
        //参数:table中的索引名
        //类型:索引对应值的类型
        Debug.Log(core.Get("Name"));
        
        core.Set("Name","admin");
        OneStringParams osp = core.Get("Func1");
        osp("admin");
        
        //相当于":"调用  0
        TransSelf ts = core.Get("Func4");
        ts(core);
    }

    public void UseLuaStruct()
    {
        LuaTable g = xLuaEnv.Instance.Global;
        //将Lua的Table导出为core
        LuaCore core= g.Get("Core");
        Debug.Log(core.Name);
        core.Func4(core);
    }
    private void OnDestroy()
    {
        xLuaEnv.Instance.Free();
    }
}












Core={}

Core.ID=123
Core.Name="root"
Core.IsWoman=false

Core.Func1=function(name)
	print("这是Core表的Func1函数,接收到c#数据"..name)
end

Core.Func2=function()
	print("这是Core表的Func2函数")
end

Core.Func3=function(self)
	print("这是Core表的Func3函数,Core表的成员变量Name是"..self.Name)
end

function Core:Func4()
	print("这是Core表的Func4函数,Core表的成员变量Name是"..self.Name)
end

你可能感兴趣的:(unity,lua,ios)