diff options
author | max-001 <maxsmits21@kpnmail.nl> | 2024-11-24 11:50:16 +0100 |
---|---|---|
committer | max-001 <maxsmits21@kpnmail.nl> | 2024-11-24 11:50:16 +0100 |
commit | 5f710fedcbbf43f65e0ef1241f22e06d42cf79b9 (patch) | |
tree | 2c97cd0a635632d5a32788ae6c9f4a99c7c4e95d /src/crepe/api/Script.h | |
parent | 2052988dba049cfa2032d01ff9e6f7bb53d084fe (diff) | |
parent | 1499363d85abedbdb571e33801b821f4dfabc638 (diff) |
Merge remote-tracking branch 'origin/master' into max/scenes
Diffstat (limited to 'src/crepe/api/Script.h')
-rw-r--r-- | src/crepe/api/Script.h | 129 |
1 files changed, 116 insertions, 13 deletions
diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 839d937..a0870cb 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -3,6 +3,9 @@ #include <vector> #include "../types.h" +#include "../util/OptionalRef.h" + +#include "EventManager.h" namespace crepe { @@ -16,13 +19,23 @@ class ComponentManager; * This class is used as a base class for user-defined scripts that can be added to game * objects using the \c BehaviorScript component. * - * \note Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as + * \info Additional *events* (like Unity's OnDisable and OnEnable) should be implemented as * member or lambda methods in derivative user script classes and registered in \c init(). + * + * \warning Concrete scripts are allowed do create a custom constructor, but the utility + * functions should not be called inside the constructor as they rely on late references that + * are only available after the constructor returns. + * + * \see feature_script */ class Script { protected: /** - * \brief Script initialization function + * \name Interface functions + * \{ + */ + /** + * \brief Script initialization function (empty by default) * * This function is called during the ScriptSystem::update() routine *before* * Script::update() if it (a) has not yet been called and (b) the \c BehaviorScript component @@ -30,24 +43,31 @@ protected: */ virtual void init() {} /** - * \brief Script update function + * \brief Script update function (empty by default) * * This function is called during the ScriptSystem::update() routine if the \c BehaviorScript * component holding this script instance is active. */ virtual void update() {} + //! \} + //! ScriptSystem calls \c init() and \c update() friend class crepe::ScriptSystem; protected: /** - * \brief Get single component of type \c T on this game object (utility) + * \name Utility functions + * \{ + */ + + /** + * \brief Get single component of type \c T on this game object * * \tparam T Type of component * * \returns Reference to component * - * \throws nullptr if this game object does not have a component matching type \c T + * \throws std::runtime_error if this game object does not have a component with type \c T */ template <typename T> T & get_component() const; @@ -55,7 +75,7 @@ protected: // cause compile-time errors /** - * \brief Get all components of type \c T on this game object (utility) + * \brief Get all components of type \c T on this game object * * \tparam T Type of component * @@ -64,25 +84,108 @@ protected: template <typename T> RefVector<T> get_components() const; + /** + * \brief Log a message using Log::logf + * + * \tparam Args Log::logf parameters + * \param args Log::logf parameters + */ + template <typename... Args> + void logf(Args &&... args); + + /** + * \brief Subscribe to an event with an explicit channel + * \see EventManager::subscribe + */ + template <typename EventType> + void subscribe(const EventHandler<EventType> & callback, event_channel_t channel); + /** + * \brief Subscribe to an event on EventManager::CHANNEL_ALL + * \see EventManager::subscribe + */ + template <typename EventType> + void subscribe(const EventHandler<EventType> & callback); + + //! \} + +private: + /** + * \brief Internal subscribe function + * + * This function exists so certain template specializations of Script::subscribe can be + * explicitly deleted, and does the following: + * - Wrap the user-provided callback in a check that tests if the parent BehaviorScript + * component is still active + * - Store the subscriber handle returned by the event manager so this listener is + * automatically unsubscribed at the end of this Script instance's life + * + * \tparam EventType concrete Event class + * \param callback User-provided callback function + * \param channel Event channel (may have been overridden by template specializations) + */ + template <typename EventType> + void subscribe_internal(const EventHandler<EventType> & callback, event_channel_t channel); + protected: - // NOTE: Script must have a constructor without arguments so the game programmer doesn't need - // to manually add `using Script::Script` to their concrete script class. + // NOTE: This must be the only constructor on Script, see "Late references" below Script() = default; //! Only \c BehaviorScript instantiates Script friend class BehaviorScript; +public: + // std::unique_ptr destroys script + virtual ~Script(); + +private: + Script(const Script &) = delete; + Script(Script &&) = delete; + Script & operator=(const Script &) = delete; + Script & operator=(Script &&) = delete; + private: - // These references are set by BehaviorScript immediately after calling the constructor of - // Script. - game_object_id_t game_object_id = -1; - ComponentManager * component_manager_ref = nullptr; - // TODO: use OptionalRef instead of pointer + /** + * \name Late references + * + * These references are set by BehaviorScript immediately after calling the constructor of + * Script. + * + * \note Script must have a constructor without arguments so the game programmer doesn't need + * to manually add `using Script::Script` to their concrete script class if they want to + * implement a non-default constructor (e.g. for passing references to their own concrete + * Script classes). + * + * \{ + */ + //! Game object ID of game object parent BehaviorScript is attached to + game_object_id_t game_object_id; + //! Reference to parent component + OptionalRef<bool> active; + //! Reference to component manager instance + OptionalRef<ComponentManager> component_manager; + //! Reference to event manager instance + OptionalRef<EventManager> event_manager; + //! \} private: //! Flag to indicate if \c init() has been called already bool initialized = false; + //! List of subscribed events + std::vector<subscription_t> listeners; }; +/** + * \brief Subscribe to CollisionEvent for the current GameObject + * + * This is a template specialization for Script::subscribe which automatically sets the event + * channel so the callback handler is only called for CollisionEvent events that apply to the + * current GameObject the parent BehaviorScript is attached to. + */ +template <> +void Script::subscribe(const EventHandler<CollisionEvent> & callback); +template <> +void Script::subscribe(const EventHandler<CollisionEvent> & callback, event_channel_t) + = delete; + } // namespace crepe #include "Script.hpp" |