DelegateBridge.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Tencent is pleased to support the open source community by making xLua available.
  3. * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
  4. * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
  5. * http://opensource.org/licenses/MIT
  6. * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
  7. */
  8. #if USE_UNI_LUA
  9. using LuaAPI = UniLua.Lua;
  10. using RealStatePtr = UniLua.ILuaState;
  11. using LuaCSFunction = UniLua.CSharpFunctionDelegate;
  12. #else
  13. using LuaAPI = XLua.LuaDLL.Lua;
  14. using RealStatePtr = System.IntPtr;
  15. using LuaCSFunction = XLua.LuaDLL.lua_CSFunction;
  16. #endif
  17. using System;
  18. using System.Collections.Generic;
  19. using System.Runtime.InteropServices;
  20. namespace XLua
  21. {
  22. public abstract class DelegateBridgeBase : LuaBase
  23. {
  24. private Type firstKey = null;
  25. private Delegate firstValue = null;
  26. private Dictionary<Type, Delegate> bindTo = null;
  27. protected int errorFuncRef;
  28. public DelegateBridgeBase(int reference, LuaEnv luaenv) : base(reference, luaenv)
  29. {
  30. errorFuncRef = luaenv.errorFuncRef;
  31. }
  32. public bool TryGetDelegate(Type key, out Delegate value)
  33. {
  34. if(key == firstKey)
  35. {
  36. value = firstValue;
  37. return true;
  38. }
  39. if (bindTo != null)
  40. {
  41. return bindTo.TryGetValue(key, out value);
  42. }
  43. value = null;
  44. return false;
  45. }
  46. public void AddDelegate(Type key, Delegate value)
  47. {
  48. if (key == firstKey)
  49. {
  50. throw new ArgumentException("An element with the same key already exists in the dictionary.");
  51. }
  52. if (firstKey == null && bindTo == null) // nothing
  53. {
  54. firstKey = key;
  55. firstValue = value;
  56. }
  57. else if (firstKey != null && bindTo == null) // one key existed
  58. {
  59. bindTo = new Dictionary<Type, Delegate>();
  60. bindTo.Add(firstKey, firstValue);
  61. firstKey = null;
  62. firstValue = null;
  63. bindTo.Add(key, value);
  64. }
  65. else
  66. {
  67. bindTo.Add(key, value);
  68. }
  69. }
  70. public virtual Delegate GetDelegateByType(Type type)
  71. {
  72. return null;
  73. }
  74. }
  75. public static class HotfixDelegateBridge
  76. {
  77. #if (UNITY_IPHONE || UNITY_TVOS) && !UNITY_EDITOR
  78. [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
  79. public static extern bool xlua_get_hotfix_flag(int idx);
  80. [DllImport("__Internal", CallingConvention = CallingConvention.Cdecl)]
  81. public static extern void xlua_set_hotfix_flag(int idx, bool flag);
  82. #else
  83. public static bool xlua_get_hotfix_flag(int idx)
  84. {
  85. return (idx < DelegateBridge.DelegateBridgeList.Length) && (DelegateBridge.DelegateBridgeList[idx] != null);
  86. }
  87. #endif
  88. public static DelegateBridge Get(int idx)
  89. {
  90. return DelegateBridge.DelegateBridgeList[idx];
  91. }
  92. public static void Set(int idx, DelegateBridge val)
  93. {
  94. if (idx >= DelegateBridge.DelegateBridgeList.Length)
  95. {
  96. DelegateBridge[] newList = new DelegateBridge[idx + 1];
  97. for (int i = 0; i < DelegateBridge.DelegateBridgeList.Length; i++)
  98. {
  99. newList[i] = DelegateBridge.DelegateBridgeList[i];
  100. }
  101. DelegateBridge.DelegateBridgeList = newList;
  102. }
  103. DelegateBridge.DelegateBridgeList[idx] = val;
  104. #if (UNITY_IPHONE || UNITY_TVOS) && !UNITY_EDITOR
  105. xlua_set_hotfix_flag(idx, val != null);
  106. #endif
  107. }
  108. }
  109. public partial class DelegateBridge : DelegateBridgeBase
  110. {
  111. internal static DelegateBridge[] DelegateBridgeList = new DelegateBridge[0];
  112. public static bool Gen_Flag = false;
  113. public DelegateBridge(int reference, LuaEnv luaenv) : base(reference, luaenv)
  114. {
  115. }
  116. public void PCall(IntPtr L, int nArgs, int nResults, int errFunc)
  117. {
  118. if (LuaAPI.lua_pcall(L, nArgs, nResults, errFunc) != 0)
  119. luaEnv.ThrowExceptionFromError(errFunc - 1);
  120. }
  121. #if HOTFIX_ENABLE
  122. private int _oldTop = 0;
  123. private Stack<int> _stack = new Stack<int>();
  124. public void InvokeSessionStart()
  125. {
  126. System.Threading.Monitor.Enter(luaEnv.luaEnvLock);
  127. var L = luaEnv.L;
  128. _stack.Push(_oldTop);
  129. _oldTop = LuaAPI.lua_gettop(L);
  130. LuaAPI.load_error_func(L, luaEnv.errorFuncRef);
  131. LuaAPI.lua_getref(L, luaReference);
  132. }
  133. public void Invoke(int nRet)
  134. {
  135. int error = LuaAPI.lua_pcall(luaEnv.L, LuaAPI.lua_gettop(luaEnv.L) - _oldTop - 2, nRet, _oldTop + 1);
  136. if (error != 0)
  137. {
  138. var lastOldTop = _oldTop;
  139. _oldTop = _stack.Pop();
  140. System.Threading.Monitor.Exit(luaEnv.luaEnvLock);
  141. luaEnv.ThrowExceptionFromError(lastOldTop);
  142. }
  143. }
  144. public void InvokeSessionEnd()
  145. {
  146. LuaAPI.lua_settop(luaEnv.L, _oldTop);
  147. _oldTop = _stack.Pop();
  148. System.Threading.Monitor.Exit(luaEnv.luaEnvLock);
  149. }
  150. public TResult InvokeSessionEndWithResult<TResult>()
  151. {
  152. if (LuaAPI.lua_gettop(luaEnv.L) < _oldTop + 2)
  153. {
  154. InvokeSessionEnd();
  155. throw new InvalidOperationException("no result!");
  156. }
  157. try
  158. {
  159. TResult ret;
  160. luaEnv.translator.Get(luaEnv.L, _oldTop + 2, out ret);
  161. return ret;
  162. }
  163. finally
  164. {
  165. InvokeSessionEnd();
  166. }
  167. }
  168. public void InParam<T>(T p)
  169. {
  170. try
  171. {
  172. luaEnv.translator.PushByType(luaEnv.L, p);
  173. }
  174. catch (Exception e)
  175. {
  176. InvokeSessionEnd();
  177. throw e;
  178. }
  179. }
  180. public void InParams<T>(T[] ps)
  181. {
  182. try
  183. {
  184. for (int i = 0; i < ps.Length; i++)
  185. {
  186. luaEnv.translator.PushByType<T>(luaEnv.L, ps[i]);
  187. }
  188. }
  189. catch (Exception e)
  190. {
  191. InvokeSessionEnd();
  192. throw e;
  193. }
  194. }
  195. //pos start from 0
  196. public void OutParam<TResult>(int pos, out TResult ret)
  197. {
  198. if (LuaAPI.lua_gettop(luaEnv.L) < _oldTop + 2 + pos)
  199. {
  200. InvokeSessionEnd();
  201. throw new InvalidOperationException("no result in " + pos);
  202. }
  203. try
  204. {
  205. luaEnv.translator.Get(luaEnv.L, _oldTop + 2 + pos, out ret);
  206. }
  207. catch (Exception e)
  208. {
  209. InvokeSessionEnd();
  210. throw e;
  211. }
  212. }
  213. #endif
  214. }
  215. }