unity3d热更新插件乌卢阿学习整理

前言
IOS不能热更新,不是因为不能用反射,是因为
System.Reflection.Assembly.Load无法使用
System.Reflection.Emit无法使用
System.CodeDom.Compiler无法使用
这三个不能用,就把传统dotnet动态路径坑死了
为啥“这三个不能用,就把传统dotnet动态路径坑死了”呢
动态载入dll或者cs的方法就这几个,IOS下不能动态载入dll或者cs文件,已经编译进去的没事
============================================== =========
尽量只把U3D当一个渲染引擎来看待,不然你会发现热更资源很悲剧,资源一定要与逻辑分开,因为U3D用的是类的序列化,后期改动会导致前面导出的资源不能用。就和开发AS3游戏差不多了。可以这么理解
1.prefab尽量不去绑定脚本,尽量在代码里AddComponent <接口实现脚本>,在实例预制的GetComponent <接口脚本>。接口操作
2.prefab可以绑定那些不会再改动的脚本
=============================== ======= ====================插件下载地址:

http://ulua.org/

toLua下载地址:

https://github.com/topameng/CsToLua

阿萌对ULUA1.03的BUG修改文章:

http://user.qzone.qq.com/5281069/blog/1408526450?ptlang=2052&ADUIN=522414019&ADSESSION=1425950543&ADTAG=CLIENT.QQ.5396_.0&ADPUBNO=26442

 

写LUA相关的工具

BabeLua-vs2012-和vs2013插件:

设置参考http://www.cocoachina.com/bbs/read.php?tid=205043

使用技巧http://blog.csdn.net/babestudio

LuaStudio,请使用管理员管理员权限,否则会挂死!

乌卢阿插件导入到unity3d常见问题

导入乌卢阿插件运行自带的例子报错问题:DllNotFoundException:这个在其老外写的自述里已经说了如何解决。

(1)将插件目录放到最外面,重启统一。

(2)真机没有打包libulua.so进包导致,或者模拟器也有些设置不对。打包的时候把libulua.so打包进库\ armeabi-V7A

EntryPointNotFoundExcept ion:  解决方案:

EntryPointNotFoundExcept 离子:这个类型错误不太单一,可选择下面2中方法解决:(方案1)把除了资产跟ProjectSettings目录之外的都删除掉,重新打开工程(方案2)如果在MAC上,选择IOS平台,很容易出现,切换到MAC / PC平台基本上就解决了,你不能要求在MAC下一定要运行IOS的动态库。

0.16框架报错解决办法:

0.16框架基于u3d4.6,所以在老版本的u3d打开会报错,如果是老版本的话把LuaWrap除了基本目录外所有的Wrapcs文件删掉,然后lua清除菜单调用下就好了。

试图  以  指数  全球  “UnityEngine”:

uaScriptException:[string“define.lua”]:1:尝试indexglobal’UnityEngine’(一个零值)解决:生成包装文件。

tolua  c#简单使用方法

打开编辑器/ BindLua.cs文件,在静态BindType [] binding = newBindType []变量末尾一行加入要导入的cs类,比如资源类,保存等u3d编译完后,选择“Lua / GenLuaBinding Files”编译即可, 以后就可以在LUA里面使用此类了,而不要导入进来。映射公共成员

C#里面有个编辑器工具类可以用Wrap映射到lua里使用
public static class LuaBinder {
  publicstatic void Bind(IntPtr L){
      ObjectWrap.Register(L);
  }
}

这个等价于我们之前在LUA中写的
luanet.import_type( “UnityEngine.Object”)

lua脚本里在定义基础类型的时候
Object = luanet.import_type(“UnityEngine.Object”)
Object = UnityEngine.Object
这两种写法有区别吗,还是随便写哪个都行?
用后效率高。前者是反射

_lua_tocbuff是阿萌自己添加的,用于xml
_luaopen_ffi是luajit的,
_luaopen_luaXML
删除函数声明即可

LUA的循环库可以正常用在乌卢阿吗里
看库是否用到了C ++代码了

自己直接拿lua5.1源码编的ulua.dll
Windows下用可以用vs编吧,我把那个lua_wrap.c也添加了
如果你的错误是找不到入口,就加这个宏,LUA_BUILD_AS_DLL,具体查一下读我。

加上这个_GT(typeof(JsonObject)),点击GEN LUAWRAPPER后统一直接就崩溃了

记得嵌套2层以上的模板就不行了,如词典>

最后发布程序的时候,会包很多错,是由于TOLUA无法识别代码中加了编辑器运行的条件编译判断,所以手动注释掉与这相关的代码不报错就好,就能正常编译打包程序了。

如何在LUA中遍历CSHARP的数组

 LuaTable mMap;

    字典mLuaMap;

    公开LuaTable地图{

        得到{

            if(mMap == null){

                mLuaMap = new Dictionary();

                mMap = TTLuaMain.Instance.luaState.NewTable();

                for(int i = 0,iMax = mVariables.Length; i <iMax; i ++){

                    var val = mVariables [i];

                    mMap [val.name] = val.val;

                    mLuaMap.Add(val.name,val);

                }

            }

            返回mMap

        }

}

LuaVariable  是我自定义的类型,你可以随便传,  这个是指我在C#里写的数组类型

核心思想就是把你C#数组里面的东西,放入表,如果是单纯的数据类型,你可以直接lua里面为  0,maxlength   如果是字典类型的,你就要转换。

比如我这里:

通过TOLUA,把Collider2d类型注册给ULUA,直接lua里面为  0,maxlength  遍历。

再贴上乌卢阿群主写的范例:

在lua里怎么遍历C#的对象数组:


通过IEnumerator:

  

乌卢阿自带的案例

2015年3月26日15:58:22补充说明,升级到U3D5.0.0F4,U3DAPI改了很多,都得用getcomponent函数,以前直接THIS.transform已经不能用了,所以自带的小案例会报错。

02_CreateGameObject:

这里我先写个最平常不过的U3D下的C#脚本

======================= ExtendMonoScript的.cs ================

public class ExtendMonoScript:MonoBehaviour {

    voidStart(){     

  AAA();  

}   

public void aaa(){ 

     Debug.Log(this +“普通的函数调用!”); 

  }

   public static voidStaticMethod(){

      的debug.log( “公有静态函数!!”);

  } 

  private static voidPirvateStaticMethod(){  

    的debug.log( “私有静态函数!!”);

  }   

public void ObjMethod(){   

   的debug.log( “公有成员函数!!”);

  }  

private void PrivateObjMethod(){   

   的debug.log( “私有成员函数!!”); 

  }

}

======================= ExtendMonoScript的.cs ================


======================= CreateGameObject.cs ===============

使用UnityEngine;
使用System.Collections;
// lua
使用LuaInterface;

public class CreateGameObject:MonoBehaviour {

    privatestring script = @“
           luanet.load_assembly( 'UnityEngine')
           GameObject = luanet.import_type('UnityEngine.GameObject')
           luanet.load_assembly( '汇编CSHARP')

           local newGameObj = GameObject('Creat_GameObj_In_Lua')
           newGameObj:AddComponent( 'ExtendMonoScript')
       “;
   
    void Start(){
       LuaState l = new LuaState();
       l.DoString(脚本);
    }
}
======================= CreateGameObject.cs ===============

load_assembly加载程序集,这样LUA才能使用其API

import_type导入类型,这样LUA才能使用改类型

newGameObj:AddComponent( 'ExtendMonoScript')这里注意初学LUA,“:”,“”与的区别

DoString(脚本);真正使用乌卢阿插件时不要用这个,因为效率低下。


03_AccessingLuaVariables:

======================== AccessingLuaVariables.cs ======================= ===

使用UnityEngine;
使用System.Collections;
使用LuaInterface;

public class AccessingLuaVariables:MonoBehaviour {

    //对象调用函数用:load_assembly是载入程序集import_type是引入类型
    // ..相当于是C#里的字符串+,就是连接字符串的意思
    //地方性表示局部变量,没写都为全局变量
    // {}表示TABLE,LUA里数组,链表等等结构都使用该方式模拟出来
    //table.insert表示追加,在数组最后插入一个新元素
    privatestring script = @“
           luanet.load_assembly( 'UnityEngine')
           GameObject = luanet.import_type('UnityEngine.GameObject')

           g_particles = {}

           对于i = 1,g_Objs2Spawn,1 do
               local newGameObj = GameObject('NewObj'.. tostring(i))
               本地ps = newGameObj:AddComponent('ParticleSystem')
               PS:停止()

               table.insert(g_particles,ps)
           结束

           g_var2read = 42

           g_array = {}
           对于i = 1,5,1
               table.insert(g_array,i)
           结束
       “;

   
    void Start(){
       LuaState l = new LuaState();
       //给全局变量赋值
       l [“g_Objs2Spawn”] = 5;
       l.DoString(脚本);

       //取得全局变量
       print(“从lua读取”+ l [“g_var2read”]。ToString());

       //将lua表作为LuaTable对象
       LuaTable粒子=(LuaTable)l [“g_particles”];
       
       //表中值的典型值
       foreach(ParticleSystem ps in particle.Values)
       {
           ps.Play();
       }

       l [“g_var2read”] = 48;
       Debug.Log(“从lua读取”+ l [“g_var2read”]。ToString());
       // Lua里数值都是当的双,动态类型,不需要强制类型转换
       // float akb =(float)l [“var2read”]; //错误
       // int akb =(int)l [“var2read”]; //错误
       double akb =(double)l [“g_var2read”]; //好
       的debug.log(AKB);
       l [“g_var2read”] =“AKB48”; //好
       Debug.Log(“从lua读取,赋值字符串后:”+ l [“g_var2read”]。ToString());
       string str =(string)l [“g_var2read”]; // 好
       Debug.Log(“str =”+ str);

       LuaTable nums =(LuaTable)l [“g_array”];
       foreach(double num in nums.Values){
           Debug.Log(“num =”+ num);
       }
       foreach(双键在nums.Keys中){
           Debug.Log(“关键字=”+键);
       }
       //Debug.Log("nums[1] =“+ nums [”1“]。ToString()); //错误
    }
}
======================== AccessingLuaVariables.cs ======================= ===

群共享的小框架SimpleFramework

baseLua =桥,继承baselua的c#类一般不需要导出包装。

V0.2.0发布EXE调整:

首先直接发布EXE报错:

修改打包编辑器脚本:

直接简单的把打包目标改成WIN,重新打包。

载入AB的资源管理脚本:


可以看到这里对路径只写了安卓和IOS平台的判断,再就是是否是调试版的判断。改完后,按GUI的提示改下常量为DEBUG模式,以拿到路径。这样发布EXE就正常了。

=================启动SimpleFramework_v0.1.5的服务端问题======================

启动  SimpleFramework_v0.1.5 的服务端这个是什么问题

2014年10月12日  10:46:48573  [7128]  错误  DefaultBootstrap  –  失败  来  创建  服务器  实例  ManagementServer!

System.Reflection.TargetInvocationExceptio n:  调用的目标发生了异常  —>  System.TypeInitializationException :  “ SuperSocket.ServerManager.ManagementServer ”的类型初始值设定项引发异常  —>  System.IO.FileNotFoundException:  未能加载文件或程序集“ Newtonsoft.Json,  Version = 4.5.0.0,  Culture = neutral,  PublicKeyToken = 30ad4fe6b2a6aeed ”或它的某一依赖项。系统找不到指定的文件。 

安装.net  4 ,没有找到json 的dll,已经在目录里面有了,跟exe同目录

把这个,Newtonsoft.Json.dll考到  调试文件执行  同目录就可以了。

================================================== ============================

TOLUA,封装C#与LUA通信原理:

 LuaDLL.lua_pushstdcallcfunction(L,IndexArray);       
 LuaDLL.lua_rawset(L,-3);      
 LuaDLL.lua_pushstring(L,“__gc”);    
 LuaDLL.lua_pushstdcallcfunction(L,__gc);
 LuaDLL.lua_rawset(L,-3);

pushstring是把toluaindex压栈,dostring我记得是执行这段字符串,生成闭包,最后是以toluaindex为键。闭包为值存放在注册表,这样可以不被LUA直接访问到,如果我记得不错的话,rawset是绕过元表直接设置表,索引表示的是LUA堆栈中对象的索引位置。

怎么知道指数是多少呢?如这个里面的-3


-3是luanet  数组,就是个栈,而且第一个-3和第二个是不一样的,理解栈,压栈,出栈就好了,前面四句就是luanetarray [_index] =函数,settop是设置栈顶,这里为0是清空栈。

最后的-3是不是倒数第3次的push.lua_pushstdcallcfunction(L,  IndexArray);  是这行的IndexArray吗?

非也,是那个元表,rawset只是把键  和值弹出而已,元表留在栈顶,实际上这是给这个元表加一个键为_gc,value为gc函数的键值。

=====================================

我为nlua小框架:

使用步骤:

//附带地鼠资源打包教程和编辑脚本测试工程教程:
1.执行编辑器菜单ME工具/清理缓存,让一切重新开始
2.执行编辑器菜单ME工具/把Atlas目录下的.png图片作为图集资源并放入数据目录。
3.在项目窗体内鼠标点选选中资产/构建/ GUI,然后执行编辑器菜单MEtools /独立打包选中目录下的各个对象并放入数据目录。
4.执行编辑器菜单MEtools /制作更新包:把数据目录压缩为一个zip包并入StreamingAssets目录。
通过以上步骤完成资源和升级包的制作了。
如果在编辑器进行代码修改或者资源修改,请重复以上步骤。
如果仅仅修改资产/数据/ LUA下的逻辑脚本,您只需要执行以上的1和4步骤

我fornlua把插件下面的x86和x86_64两个文件夹删除掉,就能发布android了。

我为nlua编译选项推荐使用
UNITY_3D; USE_KERALUA; LUA_CORE; CATCH_EXCEPTIONS即使
使用c版lua加速,也可解决打印(调试。日志)中文日志显示乱码问题。

参考一下ME游戏框架,全局就一个luastate,
ME框架的思路就是一个GameObject对应挂个LuaBehaviour.cs脚本,这个LuaBehaviour.cs脚本DoFile一个
lua 脚本,lua脚本和LuaBehaviour.cs交互控制。全局就有一个luastate,每个脚本其实就是一个表。

============================= =========================
U3D5的更新:

各位使用MAC + U5 64的同学,如果遇到编辑器环境下luastate ==空的情况,下载libulua.zip替换其底层库,可暂时绕过此问题,将来有时间研究下。