LuaScriptInstance.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //
  2. // Copyright (c) 2008-2013 the Urho3D project.
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to deal
  6. // in the Software without restriction, including without limitation the rights
  7. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. // copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. // THE SOFTWARE.
  21. //
  22. #include "Precompiled.h"
  23. #include "Context.h"
  24. #include "Log.h"
  25. #include "LuaFile.h"
  26. #include "LuaScript.h"
  27. #include "LuaScriptInstance.h"
  28. #include "ResourceCache.h"
  29. #include "ProcessUtils.h"
  30. extern "C"
  31. {
  32. #include <lua.h>
  33. #include <lualib.h>
  34. #include <lauxlib.h>
  35. }
  36. #include "tolua++.h"
  37. namespace Urho3D
  38. {
  39. LuaScriptInstance::LuaScriptInstance(Context* context) :
  40. Component(context),
  41. scriptObjectRef_(LUA_REFNIL)
  42. {
  43. luaScript_ = GetSubsystem<LuaScript>();
  44. luaState_ = luaScript_->GetLuaState();
  45. }
  46. LuaScriptInstance::~LuaScriptInstance()
  47. {
  48. ReleaseObject();
  49. }
  50. void LuaScriptInstance::RegisterObject(Context* context)
  51. {
  52. context->RegisterFactory<LuaScriptInstance>();
  53. }
  54. bool LuaScriptInstance::CreateObject(const String& scriptObjectType)
  55. {
  56. if (scriptObjectType_ == scriptObjectType)
  57. return true;
  58. ReleaseObject();
  59. int top = lua_gettop(luaState_);
  60. lua_getglobal(luaState_, "CreateScriptObjectInstance");
  61. if (!lua_isfunction(luaState_, -1))
  62. {
  63. LOGERROR("Could not find lua function CreateScriptObjectInstance");
  64. lua_settop(luaState_, top);
  65. return false;
  66. }
  67. // Get table as first paramter.
  68. lua_getglobal(luaState_, scriptObjectType.CString());
  69. if (!lua_istable(luaState_, -1))
  70. {
  71. LOGERROR("Could not find lua table " + scriptObjectType);
  72. lua_settop(luaState_, top);
  73. return false;
  74. }
  75. // Push this as second parameter.
  76. tolua_pushusertype(luaState_, (void*)this, "LuaScriptInstance");
  77. // Call ObjectType:new function.
  78. if (lua_pcall(luaState_, 2, 1, 0) != 0)
  79. {
  80. const char* message = lua_tostring(luaState_, -1);
  81. LOGERROR("Execute Lua function failed: " + String(message));
  82. lua_settop(luaState_, top);
  83. return false;
  84. }
  85. scriptObjectType_ = scriptObjectType;
  86. scriptObjectRef_ = luaL_ref(luaState_, LUA_REGISTRYINDEX);
  87. return true;
  88. }
  89. bool LuaScriptInstance::CreateObject(const String& fileName, const String& scriptObjectType)
  90. {
  91. ResourceCache* cache = GetSubsystem<ResourceCache>();
  92. LuaFile* luaFile = cache->GetResource<LuaFile>(fileName);
  93. if (!luaFile)
  94. return false;
  95. if (!luaFile->LoadAndExecute(luaState_))
  96. return false;
  97. return CreateObject(scriptObjectType);
  98. }
  99. void LuaScriptInstance::ScriptSubscribeToEvent(const String& eventName, const String& functionName)
  100. {
  101. StringHash eventType(eventName);
  102. String realFunctionName = functionName.Replaced(":", ".");
  103. int functionRef = LUA_REFNIL;
  104. if (luaScript_->FindFunction(realFunctionName))
  105. functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
  106. if (functionRef != LUA_REFNIL)
  107. {
  108. SubscribeToEvent(eventType, HANDLER(LuaScriptInstance, HandleEvent));
  109. eventTypeToFunctionRefMap_[eventType] = functionRef;
  110. }
  111. }
  112. void LuaScriptInstance::ScriptUnsubscribeFromEvent(const String& eventName)
  113. {
  114. StringHash eventType(eventName);
  115. HashMap<StringHash, int>::Iterator i = eventTypeToFunctionRefMap_.Find(eventType);
  116. if (i != eventTypeToFunctionRefMap_.End())
  117. {
  118. UnsubscribeFromEvent(eventType);
  119. if (i->second_ != LUA_REFNIL)
  120. luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
  121. eventTypeToFunctionRefMap_.Erase(i);
  122. }
  123. }
  124. void LuaScriptInstance::ScriptUnsubscribeFromAllEvents()
  125. {
  126. if (eventTypeToFunctionRefMap_.Empty())
  127. return;
  128. UnsubscribeFromAllEvents();
  129. for (HashMap<StringHash, int>::Iterator i = eventTypeToFunctionRefMap_.Begin(); i != eventTypeToFunctionRefMap_.End(); ++i)
  130. if (i->second_ != LUA_REFNIL)
  131. luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
  132. eventTypeToFunctionRefMap_.Clear();
  133. }
  134. void LuaScriptInstance::ScriptSubscribeToEvent(void* object, const String& eventName, const String& functionName)
  135. {
  136. StringHash eventType(eventName);
  137. String realFunctionName = functionName.Replaced(":", ".");
  138. Object* sender = (Object*)object;
  139. int functionRef = LUA_REFNIL;
  140. if (luaScript_->FindFunction(realFunctionName))
  141. functionRef = luaL_ref(luaState_, LUA_REGISTRYINDEX);
  142. if (functionRef != LUA_REFNIL)
  143. {
  144. SubscribeToEvent(sender, eventType, HANDLER(LuaScriptInstance, HandleObjectEvent));
  145. objectToEventTypeToFunctionRefMap_[sender][eventType] = functionRef;
  146. }
  147. }
  148. void LuaScriptInstance::ScriptUnsubscribeFromEvent(void* object, const String& eventName)
  149. {
  150. StringHash eventType(eventName);
  151. Object* sender = (Object*)object;
  152. HashMap<StringHash, int>::Iterator i = objectToEventTypeToFunctionRefMap_[sender].Find(eventType);
  153. if (i != objectToEventTypeToFunctionRefMap_[sender].End())
  154. {
  155. UnsubscribeFromEvent(sender, eventType);
  156. if (i->second_ != LUA_REFNIL)
  157. luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
  158. objectToEventTypeToFunctionRefMap_[sender].Erase(i);
  159. }
  160. }
  161. void LuaScriptInstance::ScriptUnsubscribeFromEvents(void* object)
  162. {
  163. Object* sender = (Object*)object;
  164. HashMap<Object*, HashMap<StringHash, int> >::Iterator it = objectToEventTypeToFunctionRefMap_.Find(sender);
  165. if (it == objectToEventTypeToFunctionRefMap_.End())
  166. return;
  167. UnsubscribeFromEvents(sender);
  168. HashMap<StringHash, int>& eventTypeToFunctionRefMap = it->second_;
  169. for (HashMap<StringHash, int>::Iterator i = eventTypeToFunctionRefMap.Begin(); i != eventTypeToFunctionRefMap.End(); ++i)
  170. {
  171. if (i->second_ != LUA_REFNIL)
  172. luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
  173. }
  174. objectToEventTypeToFunctionRefMap_.Erase(it);
  175. }
  176. void LuaScriptInstance::HandleEvent(StringHash eventType, VariantMap& eventData)
  177. {
  178. if (scriptObjectRef_ == LUA_REFNIL)
  179. return;
  180. int functionRef = eventTypeToFunctionRefMap_[eventType];
  181. if (functionRef == LUA_REFNIL)
  182. return;
  183. CallEventHandler(functionRef, eventType, eventData);
  184. }
  185. void LuaScriptInstance::HandleObjectEvent(StringHash eventType, VariantMap& eventData)
  186. {
  187. if (scriptObjectRef_ == LUA_REFNIL)
  188. return;
  189. Object* object = GetEventSender();
  190. int functionRef = objectToEventTypeToFunctionRefMap_[object][eventType];
  191. if (functionRef == LUA_REFNIL)
  192. return;
  193. CallEventHandler(functionRef, eventType, eventData);
  194. }
  195. void LuaScriptInstance::CallEventHandler(int functionRef, StringHash eventType, VariantMap& eventData )
  196. {
  197. int top = lua_gettop(luaState_);
  198. // Push function.
  199. lua_rawgeti(luaState_, LUA_REGISTRYINDEX, functionRef);
  200. // Push script object.
  201. lua_rawgeti(luaState_, LUA_REGISTRYINDEX, scriptObjectRef_);
  202. // Push event type.
  203. tolua_pushusertype(luaState_, (void*)&eventType, "StringHash");
  204. // Push event data.
  205. tolua_pushusertype(luaState_, (void*)&eventData, "VariantMap");
  206. if (lua_pcall(luaState_, 3, 0, 0) != 0)
  207. {
  208. const char* message = lua_tostring(luaState_, -1);
  209. LOGERROR("Execute Lua function failed: " + String(message));
  210. lua_settop(luaState_, top);
  211. return;
  212. }
  213. }
  214. void LuaScriptInstance::ReleaseObject()
  215. {
  216. if (scriptObjectRef_ == LUA_REFNIL)
  217. return;
  218. // Unref script object.
  219. luaL_unref(luaState_, LUA_REGISTRYINDEX, scriptObjectRef_);
  220. scriptObjectRef_ = LUA_REFNIL;
  221. // Unref Lua function.
  222. for (HashMap<StringHash, int>::Iterator i = eventTypeToFunctionRefMap_.Begin(); i != eventTypeToFunctionRefMap_.End(); ++i)
  223. luaL_unref(luaState_, LUA_REGISTRYINDEX, i->second_);
  224. for (HashMap<Object*, HashMap<StringHash, int> >::Iterator i = objectToEventTypeToFunctionRefMap_.Begin();
  225. i != objectToEventTypeToFunctionRefMap_.End(); ++i)
  226. {
  227. for (HashMap<StringHash, int>::Iterator j = i->second_.Begin(); j != i->second_.End(); ++j)
  228. luaL_unref(luaState_, LUA_REGISTRYINDEX, j->second_);
  229. }
  230. int top = lua_gettop(luaState_);
  231. lua_getglobal(luaState_, "DestroyScriptObjectInstance");
  232. if (!lua_isfunction(luaState_, -1))
  233. {
  234. LOGERROR("Could not find lua function DestroyScriptObjectInstance");
  235. lua_settop(luaState_, top);
  236. return;
  237. }
  238. // Push this as second parameter.
  239. tolua_pushusertype(luaState_, (void*)this, "LuaScriptInstance");
  240. if (lua_pcall(luaState_, 1, 0, 0) != 0)
  241. {
  242. const char* message = lua_tostring(luaState_, -1);
  243. LOGERROR("Execute Lua function failed: " + String(message));
  244. lua_settop(luaState_, top);
  245. return;
  246. }
  247. }
  248. }