ScriptExports.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. //========================================================================
  2. // ScriptExports.cpp
  3. //
  4. // Part of the GameCode4 Application
  5. //
  6. // GameCode4 is the sample application that encapsulates much of the source code
  7. // discussed in "Game Coding Complete - 4th Edition" by Mike McShaffry and David
  8. // "Rez" Graham, published by Charles River Media.
  9. // ISBN-10: 1133776574 | ISBN-13: 978-1133776574
  10. //
  11. // If this source code has found it's way to you, and you think it has helped you
  12. // in any way, do the authors a favor and buy a new copy of the book - there are
  13. // detailed explanations in it that compliment this code well. Buy a copy at Amazon.com
  14. // by clicking here:
  15. // http://www.amazon.com/gp/product/1133776574/ref=olp_product_details?ie=UTF8&me=&seller=
  16. //
  17. // There's a companion web site at http://www.mcshaffry.com/GameCode/
  18. //
  19. // The source code is managed and maintained through Google Code:
  20. // http://code.google.com/p/gamecode4/
  21. //
  22. // (c) Copyright 2012 Michael L. McShaffry and David Graham
  23. //
  24. // This program is free software; you can redistribute it and/or
  25. // modify it under the terms of the GNU Lesser GPL v3
  26. // as published by the Free Software Foundation.
  27. //
  28. // This program is distributed in the hope that it will be useful,
  29. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  31. // http://www.gnu.org/licenses/lgpl-3.0.txt for more details.
  32. //
  33. // You should have received a copy of the GNU Lesser GPL v3
  34. // along with this program; if not, write to the Free Software
  35. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  36. //
  37. //========================================================================
  38. #include "../Unix/GameCodeStd.h"
  39. #include "../ResourceCache/ResCache.h"
  40. #include "ScriptExports.h"
  41. #include "LuaStateManager.h"
  42. #include "../EventManager/Events.h"
  43. #include <sol/sol.hpp>
  44. #include <set>
  45. //---------------------------------------------------------------------------------------------------------------------
  46. // This is the C++ listener proxy for script event listeners. It pairs a single event type with a Lua callback
  47. // function. Note that this event can be defined in C++ or Lua. It may also be sent from C++ or Lua.
  48. //
  49. // The Lua callback function should take in a table with the event data. The return value is ignored.
  50. // function Callback(eventData)
  51. //
  52. // Chapter 12, page 384
  53. //---------------------------------------------------------------------------------------------------------------------
  54. class ScriptEventListener
  55. {
  56. EventType m_eventType;
  57. sol::protected_function m_scriptCallbackFunction;
  58. public:
  59. explicit ScriptEventListener(const EventType& eventType, const sol::function scriptCallbackFunction);
  60. ~ScriptEventListener(void);
  61. EventListenerDelegate GetDelegate(void) { return MakeDelegate(this, &ScriptEventListener::ScriptEventDelegate); }
  62. void ScriptEventDelegate(IEventDataPtr pEventPtr);
  63. };
  64. //---------------------------------------------------------------------------------------------------------------------
  65. // This class manages the C++ ScriptListener objects needed for script event listeners.
  66. // Chapter 12, page 385
  67. //---------------------------------------------------------------------------------------------------------------------
  68. class ScriptEventListenerMgr
  69. {
  70. typedef std::set<ScriptEventListener*> ScriptEventListenerSet;
  71. ScriptEventListenerSet m_listeners;
  72. public:
  73. ~ScriptEventListenerMgr(void);
  74. void AddListener(ScriptEventListener* pListener);
  75. void DestroyListener(ScriptEventListener* pListener);
  76. };
  77. //---------------------------------------------------------------------------------------------------------------------
  78. // Prototypes for the functions to export. - Chapter 12, page 368
  79. //---------------------------------------------------------------------------------------------------------------------
  80. class InternalScriptExports
  81. {
  82. static ScriptEventListenerMgr* s_pScriptEventListenerMgr;
  83. public:
  84. static bool Init(void);
  85. static void Destroy(void);
  86. // resource loading
  87. static bool LoadAndExecuteScriptResource(const char* scriptResource);
  88. // event system
  89. static unsigned long RegisterEventListener(EventType eventType, sol::function callbackFunction);
  90. static bool QueueEvent(EventType eventType, sol::object eventData);
  91. // misc
  92. static void LuaLog(sol::object text);
  93. private:
  94. static std::shared_ptr<ScriptEvent> BuildEvent(EventType eventType, sol::object& eventData);
  95. };
  96. ScriptEventListenerMgr* InternalScriptExports::s_pScriptEventListenerMgr = NULL;
  97. //---------------------------------------------------------------------------------------------------------------------
  98. // Destructor
  99. //---------------------------------------------------------------------------------------------------------------------
  100. ScriptEventListenerMgr::~ScriptEventListenerMgr(void)
  101. {
  102. for (auto it = m_listeners.begin(); it != m_listeners.end(); ++it)
  103. {
  104. ScriptEventListener* pListener = (*it);
  105. delete pListener;
  106. }
  107. m_listeners.clear();
  108. }
  109. //---------------------------------------------------------------------------------------------------------------------
  110. // Adds a new listener
  111. //---------------------------------------------------------------------------------------------------------------------
  112. void ScriptEventListenerMgr::AddListener(ScriptEventListener* pListener)
  113. {
  114. m_listeners.insert(pListener);
  115. }
  116. //---------------------------------------------------------------------------------------------------------------------
  117. // Event Listener
  118. //---------------------------------------------------------------------------------------------------------------------
  119. ScriptEventListener::ScriptEventListener(const EventType& eventType, const sol::function scriptCallbackFunction)
  120. : m_scriptCallbackFunction(scriptCallbackFunction)
  121. {
  122. m_eventType = eventType;
  123. }
  124. ScriptEventListener::~ScriptEventListener(void)
  125. {
  126. IEventManager* pEventMgr = IEventManager::Get();
  127. if (pEventMgr)
  128. pEventMgr->VRemoveListener(GetDelegate(), m_eventType);
  129. }
  130. void ScriptEventListener::ScriptEventDelegate(IEventDataPtr pEvent)
  131. {
  132. GCC_ASSERT(m_scriptCallbackFunction.valid()); // this should never happen since it's validated before even creating this object
  133. // call the lua function
  134. std::shared_ptr<ScriptEvent> pScriptEvent = static_pointer_cast<ScriptEvent>(pEvent);
  135. sol::function Callback = m_scriptCallbackFunction;
  136. Callback(pScriptEvent->GetEventData());
  137. }
  138. //---------------------------------------------------------------------------------------------------------------------
  139. // Initializes the script export system
  140. //---------------------------------------------------------------------------------------------------------------------
  141. bool InternalScriptExports::Init(void)
  142. {
  143. GCC_ASSERT(s_pScriptEventListenerMgr == NULL);
  144. s_pScriptEventListenerMgr = GCC_NEW ScriptEventListenerMgr;
  145. return true;
  146. }
  147. //---------------------------------------------------------------------------------------------------------------------
  148. // Destroys the script export system
  149. //---------------------------------------------------------------------------------------------------------------------
  150. void InternalScriptExports::Destroy(void)
  151. {
  152. GCC_ASSERT(s_pScriptEventListenerMgr != NULL);
  153. SAFE_DELETE(s_pScriptEventListenerMgr);
  154. }
  155. //---------------------------------------------------------------------------------------------------------------------
  156. // Loads a script resource then executes it. This is used by the require() function in script (defined in
  157. // PreInit.lua).
  158. //---------------------------------------------------------------------------------------------------------------------
  159. bool InternalScriptExports::LoadAndExecuteScriptResource(const char* scriptResource)
  160. {
  161. Resource resource(scriptResource);
  162. std::shared_ptr<ResHandle> pResourceHandle = g_pApp->m_ResCache->GetHandle(&resource);
  163. if (pResourceHandle)
  164. return true;
  165. return false;
  166. }
  167. //---------------------------------------------------------------------------------------------------------------------
  168. // Queue's an event from the script. Returns true if the event was sent, false if not.
  169. //---------------------------------------------------------------------------------------------------------------------
  170. bool InternalScriptExports::QueueEvent(EventType eventType, sol::object eventData)
  171. {
  172. std::shared_ptr<ScriptEvent> pEvent(BuildEvent(eventType, eventData));
  173. if (pEvent)
  174. {
  175. IEventManager::Get()->VQueueEvent(pEvent);
  176. return true;
  177. }
  178. return false;
  179. }
  180. //---------------------------------------------------------------------------------------------------------------------
  181. // Builds the event to be sent or queued
  182. //---------------------------------------------------------------------------------------------------------------------
  183. std::shared_ptr<ScriptEvent> InternalScriptExports::BuildEvent(EventType eventType, sol::object& eventData)
  184. {
  185. // create the event from the event type
  186. std::shared_ptr<ScriptEvent> pEvent(ScriptEvent::CreateEventFromScript(eventType));
  187. if (!pEvent)
  188. return std::shared_ptr<ScriptEvent>();
  189. // set the event data that was passed in
  190. if (!pEvent->SetEventData(eventData))
  191. {
  192. return std::shared_ptr<ScriptEvent>();
  193. }
  194. return pEvent;
  195. }
  196. //---------------------------------------------------------------------------------------------------------------------
  197. // Instantiates a C++ ScriptListener object, inserts it into the manager, and returns a handle to it. The script
  198. // should maintain the handle if it needs to remove the listener at some point. Otherwise, the listener will be
  199. // destroyed when the program exits.
  200. //---------------------------------------------------------------------------------------------------------------------
  201. unsigned long InternalScriptExports::RegisterEventListener(EventType eventType, sol::function callbackFunction)
  202. {
  203. GCC_ASSERT(s_pScriptEventListenerMgr);
  204. if (callbackFunction.valid())
  205. {
  206. // create the C++ listener proxy and set it to listen for the event
  207. ScriptEventListener* pListener = GCC_NEW ScriptEventListener(eventType, callbackFunction);
  208. s_pScriptEventListenerMgr->AddListener(pListener);
  209. IEventManager::Get()->VAddListener(pListener->GetDelegate(), eventType);
  210. // convert the pointer to an unsigned long to use as the handle
  211. unsigned long handle = reinterpret_cast<unsigned long>(pListener);
  212. return handle;
  213. }
  214. GCC_ERROR("Attempting to register script event listener with invalid callback function");
  215. return 0;
  216. }
  217. void InternalScriptExports::LuaLog(sol::object text)
  218. {
  219. if (text.is<std::string>())
  220. {
  221. GCC_LOG("Lua", text.as<std::string>());
  222. }
  223. else
  224. {
  225. const char* typeName = lua_typename(text.lua_state(), static_cast<int>(text.get_type()));
  226. GCC_LOG("Lua", "<" + std::string(typeName) + ">");
  227. }
  228. }
  229. //---------------------------------------------------------------------------------------------------------------------
  230. // This function registers all the ScriptExports functions with the scripting system. It is called in
  231. // Application::Init().
  232. //---------------------------------------------------------------------------------------------------------------------
  233. void ScriptExports::Register(void)
  234. {
  235. sol::state_view lua = LuaStateManager::Get()->GetLuaState();
  236. sol::global_table globals = lua.globals();
  237. // init
  238. InternalScriptExports::Init();
  239. // resource loading
  240. globals["LoadAndExecuteScriptResource"] = &InternalScriptExports::LoadAndExecuteScriptResource;
  241. // actors
  242. // globals.RegisterDirect("CreateActor", &InternalScriptExports::CreateActor);
  243. // event system
  244. globals["RegisterEventListener"] = &InternalScriptExports::RegisterEventListener;
  245. // globals.RegisterDirect("RemoveEventListener", &InternalScriptExports::RemoveEventListener);
  246. globals["QueueEvent"] = &InternalScriptExports::QueueEvent;
  247. // globals.RegisterDirect("TriggerEvent", &InternalScriptExports::TriggerEvent);
  248. // process system
  249. // globals.RegisterDirect("AttachProcess", &InternalScriptExports::AttachScriptProcess);
  250. // math
  251. // LuaPlus::LuaObject mathTable = globals.GetByName("GccMath");
  252. // GCC_ASSERT(mathTable.IsTable());
  253. // mathTable.RegisterDirect("GetYRotationFromVector", &InternalScriptExports::GetYRotationFromVector);
  254. // mathTable.RegisterDirect("WrapPi", &InternalScriptExports::WrapPi);
  255. // mathTable.RegisterDirect("GetVectorFromRotation", &InternalScriptExports::GetVectorFromRotation);
  256. // misc
  257. globals["Log"] = &InternalScriptExports::LuaLog;
  258. // globals.RegisterDirect("GetTickCount", &InternalScriptExports::GetTickCount);
  259. // Physics
  260. // globals.RegisterDirect("ApplyForce", &InternalScriptExports::ApplyForce);
  261. // globals.RegisterDirect("ApplyTorque", &InternalScriptExports::ApplyTorque);
  262. }
  263. //---------------------------------------------------------------------------------------------------------------------
  264. // This function unregisters all the ScriptExports functions and gives any underlying systems a chance to destroy
  265. // themselves. It is called in the Application destructor.
  266. //---------------------------------------------------------------------------------------------------------------------
  267. void ScriptExports::Unregister(void)
  268. {
  269. InternalScriptExports::Destroy();
  270. }