ScriptEvent.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #pragma once
  2. //========================================================================
  3. // ScriptEvent.h
  4. //
  5. // Part of the GameCode4 Application
  6. //
  7. // GameCode4 is the sample application that encapsulates much of the source code
  8. // discussed in "Game Coding Complete - 4th Edition" by Mike McShaffry and David
  9. // "Rez" Graham, published by Charles River Media.
  10. // ISBN-10: 1133776574 | ISBN-13: 978-1133776574
  11. //
  12. // If this source code has found it's way to you, and you think it has helped you
  13. // in any way, do the authors a favor and buy a new copy of the book - there are
  14. // detailed explanations in it that compliment this code well. Buy a copy at Amazon.com
  15. // by clicking here:
  16. // http://www.amazon.com/gp/product/1133776574/ref=olp_product_details?ie=UTF8&me=&seller=
  17. //
  18. // There's a companion web site at http://www.mcshaffry.com/GameCode/
  19. //
  20. // The source code is managed and maintained through Google Code:
  21. // http://code.google.com/p/gamecode4/
  22. //
  23. // (c) Copyright 2012 Michael L. McShaffry and David Graham
  24. //
  25. // This program is free software; you can redistribute it and/or
  26. // modify it under the terms of the GNU Lesser GPL v3
  27. // as published by the Free Software Foundation.
  28. //
  29. // This program is distributed in the hope that it will be useful,
  30. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  31. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
  32. // http://www.gnu.org/licenses/lgpl-3.0.txt for more details.
  33. //
  34. // You should have received a copy of the GNU Lesser GPL v3
  35. // along with this program; if not, write to the Free Software
  36. // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  37. //
  38. //========================================================================
  39. //---------------------------------------------------------------------------------------------------------------------
  40. // DOCUMENTATION:
  41. //
  42. // Chapter 12. page 380
  43. //
  44. // ====================================
  45. // Script Events: Overview
  46. //
  47. // This system provides the glue that allows events to be sent to or received by the script. There is some C++ setup
  48. // involved but once done, event passing between the boundary becomes completely transparent.
  49. //
  50. // ====================================
  51. // Setup (C++):
  52. //
  53. // In order to make an event able to be seen & processed by the script, you must follow four steps:
  54. // 1) Inherit your event class from ScriptEvent
  55. // 2) Implement VBuildEventData() and VBuildEventFromScript() if necessary (see the comments above their prototypes
  56. // for details)
  57. // 3) Call the EXPORT_FOR_SCRIPT_EVENT() macro in your event subclass declaration
  58. // 4) Call the REGISTER_SCRIPT_EVENT() macro in Application::RegisterScriptEvents() or the game-specific subclass
  59. // override, as appropriate
  60. //
  61. // Once done, your event should be visible to the script. In script, the EventType table will contain a member indexed
  62. // by the event type string containing the event id. This id matches the EventType for the appropriate event.
  63. //
  64. // ====================================
  65. // Sending Events from Script:
  66. //
  67. // To send an event from script, you will need to create a table that contains the necessary data, then call the
  68. // exported QueueEvent() or SendEvent() function. The first parameter is the event type (from the EventType table)
  69. // and the second parameter is the table.
  70. //
  71. // In C++, this table is assigned to the m_eventData variable and used by your VBuildEventFromScript() implementation
  72. // to fill out your C++ members. If something goes wrong, return false and the event won't be sent. If you don't
  73. // need to receive the event on the C++ side, it doesn't matter and you can keep the default implementation of
  74. // VBuildEventFromScript().
  75. //
  76. // Events are received on the C++ side as normal. Inherit from EventListener and register for the appropriate event
  77. // type. Your receiver doesn't know nor does it care where the event came from.
  78. //
  79. // ====================================
  80. // Receiving Events in Script:
  81. //
  82. // To register an event listener in script, call the exported RegisterEventListener() function. The first parameter
  83. // is the event type (from the EventType table) and the second parameter is the callback function that's called every
  84. // time the event is triggered. The callback function should take a table as its only parameter and return nothing:
  85. // function EventCallback(eventData)
  86. //
  87. // RegisterEventListener() returns an id to your listener. When you no longer wish to receive an event, call the
  88. // exported RemoveEventListener() function and pass it this id. If you don't need to ever stop listening for the
  89. // event, it's safe to discard the id and let C++ clean it up on program exit. If your function goes out of scope,
  90. // you will still incur the performance cost of receiving the event, though no other ill effects will occur.
  91. //
  92. // Internally on the C++ side, a ScriptEventListener object is created and registered as a proxy for each script
  93. // listener. When it receives the event, it calls your ScriptEvent::VBuildEventData() to build the m_eventData table.
  94. // It then calls your registered script function, passing this table in as a parameter. Note that if you don't need
  95. // the event to be able to be received by the script, you don't need to override VBuildEventData().
  96. //---------------------------------------------------------------------------------------------------------------------
  97. #include "../EventManager/EventManager.h"
  98. #include <sol/sol.hpp>
  99. class ScriptEvent;
  100. typedef ScriptEvent* (*CreateEventForScriptFunctionType)(void); // function ptr typedef to create a script event
  101. //---------------------------------------------------------------------------------------------------------------------
  102. // These macros implement exporting events to script.
  103. //---------------------------------------------------------------------------------------------------------------------
  104. #define REGISTER_SCRIPT_EVENT(eventClass, eventType) \
  105. ScriptEvent::RegisterEventTypeWithScript(#eventClass, eventType); \
  106. ScriptEvent::AddCreationFunction(eventType, &eventClass::CreateEventForScript)
  107. #define EXPORT_FOR_SCRIPT_EVENT(eventClass) \
  108. public: \
  109. static ScriptEvent* CreateEventForScript(void) \
  110. { \
  111. return new eventClass; \
  112. }
  113. //---------------------------------------------------------------------------------------------------------------------
  114. // Script event base class. This class is meant to be subclassed by any event that can be sent or received by the
  115. // script. Note that these events are not limited to script and can be received just fine by C++ listeners.
  116. // Furthermore, since the Script data isn't built unless being received by a script listener, there's no worry about
  117. // performance.
  118. //---------------------------------------------------------------------------------------------------------------------
  119. class ScriptEvent : public BaseEventData
  120. {
  121. typedef std::map<EventType, CreateEventForScriptFunctionType> CreationFunctions;
  122. static CreationFunctions s_creationFunctions;
  123. bool m_eventDataIsValid;
  124. protected:
  125. sol::object m_eventData;
  126. public:
  127. // construction
  128. ScriptEvent(void) { m_eventDataIsValid = false; }
  129. // script event data, which should only be called from the appropriate ScriptExports functions
  130. sol::object GetEventData(void); // called when event is sent from C++ to script
  131. bool SetEventData(sol::object eventData); // called when event is sent from script to C++
  132. // Static helper functions for registering events with the script. You should call the REGISTER_SCRIPT_EVENT()
  133. // macro instead of calling this function directly. Any class that needs to be exported also needs to call the
  134. // EXPORT_FOR_SCRIPT_EVENT() inside the class declaration.
  135. static void RegisterEventTypeWithScript(const char* key, EventType type);
  136. static void AddCreationFunction(EventType type, CreateEventForScriptFunctionType pCreationFunctionPtr);
  137. static ScriptEvent* CreateEventFromScript(EventType type);
  138. protected:
  139. // This function must be overridden if you want to fire this event from C++ and have it received by the script.
  140. // If you only fire the event from the script side, this function will never be called. It's purpose is to
  141. // fill in the m_eventData member, which is then passed to the script callback function in the listener. This
  142. // is only called the first time GetEventData() is called. If the event is script-only, this function does not
  143. // need to be overridden.
  144. virtual void VBuildEventData(void);
  145. // This function must be overridden if you want to fire this event from Script and have it received by C++. If
  146. // you only fire this event from script and have it received by the script, it doesn't matter since m_eventData
  147. // will just be passed straight through. Its purpose is to fill in any C++ member variables using the data in
  148. // m_eventData (which is valid at the time of the call). It is called when the event is fired from the script.
  149. // Return false if the data is invalid in some way, which will keep the event from actually firing.
  150. virtual bool VBuildEventFromScript(void) { return true; }
  151. };