From 099d9a15c3163c86d6cb48040c07a723fb545b95 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Mon, 27 Feb 2023 12:46:02 -0800 Subject: [PATCH] Added state event. --- src/dawn/state/State.hpp | 1 + src/dawn/state/StateEvent.hpp | 33 +++++++++++++ src/dawn/state/StateOwner.hpp | 55 ++++++++++++++++----- src/dawn/state/StateProperty.hpp | 13 ++++- src/dawntictactoe/scenes/TicTacToeScene.hpp | 4 -- 5 files changed, 88 insertions(+), 18 deletions(-) create mode 100644 src/dawn/state/StateEvent.hpp diff --git a/src/dawn/state/State.hpp b/src/dawn/state/State.hpp index 91b0ed6c..41a88719 100644 --- a/src/dawn/state/State.hpp +++ b/src/dawn/state/State.hpp @@ -5,5 +5,6 @@ #pragma once +#include "StateEvent.hpp" #include "StateOwner.hpp" #include "StateProperty.hpp" \ No newline at end of file diff --git a/src/dawn/state/StateEvent.hpp b/src/dawn/state/StateEvent.hpp new file mode 100644 index 00000000..6aa72dff --- /dev/null +++ b/src/dawn/state/StateEvent.hpp @@ -0,0 +1,33 @@ +// Copyright (c) 2023 Dominic Masters +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +#pragma once +#include "assert/assert.hpp" + +namespace Dawn { + class StateOwner; + + template + class StateEvent { + private: + std::vector> listeners; + + public: + /** + * Invokes the event and emits to all of the listeners. + * + * @param args Arguments for this event to pass to the listeners. + */ + void invoke(A... args) { + auto itListeners = this->listeners.begin(); + while(itListeners != this->listeners.end()) { + (*itListeners)(args...); + ++itListeners; + } + } + + friend class StateOwner; + }; +} \ No newline at end of file diff --git a/src/dawn/state/StateOwner.hpp b/src/dawn/state/StateOwner.hpp index f7957e80..8668e402 100644 --- a/src/dawn/state/StateOwner.hpp +++ b/src/dawn/state/StateOwner.hpp @@ -4,7 +4,7 @@ // https://opensource.org/licenses/MIT #pragma once -#include "assert/assert.hpp" +#include "StateEvent.hpp" namespace Dawn { template @@ -12,15 +12,10 @@ namespace Dawn { class StateOwner { private: - std::map>> effects; + std::map>> effectListeners; + std::vector> stateUpdateListeners; public: - /** - * Invoked event listener for the subclass that listens for all changes - * to any part of this state updated. - */ - virtual void onStateUpdate() = 0; - /** * Creates a new state property and listens for its change. * @@ -46,7 +41,32 @@ namespace Dawn { */ template void useEffect(StateProperty &property, const std::function &fn) { - this->effects[(void*)&property].push_back(fn); + assertFalse(property.owner == this); + this->effectListeners[(void*)&property].push_back(fn); + } + + /** + * Listen for changes to any single state property managed by this state + * owner. + * + * @param fn Function to be invoked when any state property is updated. + */ + void useStateUpdated(const std::function &fn) { + this->stateUpdateListeners.push_back(fn); + } + + /** + * Listen for when an event is invoked by a state event. This is intended + * to allow for cross-state-owner communication in a simple and effective + * way. + * + * @tparam A The arguments from the state event that are calledback. + * @param event The event that is being subscribed to. + * @param fn The function to be inokved on event trigger. + */ + template + void useEvent(StateEvent &event, const std::function &fn) { + event.listeners.push_back(fn); } /** @@ -60,14 +80,19 @@ namespace Dawn { */ template void _statePropertyUpdated(StateProperty *prop, V n, V o) { - this->onStateUpdate(); - - auto eff = &this->effects[prop]; + auto eff = &this->effectListeners[prop]; + auto itEff = eff->begin(); while(itEff != eff->end()) { (*itEff)(); ++itEff; } + + auto itUpdate = this->stateUpdateListeners.begin(); + while(itUpdate != this->stateUpdateListeners.end()) { + (*itUpdate)(); + ++itUpdate; + } } /** @@ -79,7 +104,11 @@ namespace Dawn { */ template void _statePropertyDestroyed(StateProperty *prop) { - this->effects.erase((void*)prop); + this->effectListeners.erase((void*)prop); + } + + virtual ~StateOwner() { + } }; } \ No newline at end of file diff --git a/src/dawn/state/StateProperty.hpp b/src/dawn/state/StateProperty.hpp index 92d53c24..f41bbaf6 100644 --- a/src/dawn/state/StateProperty.hpp +++ b/src/dawn/state/StateProperty.hpp @@ -4,15 +4,23 @@ // https://opensource.org/licenses/MIT #pragma once -#include "StateOwner.hpp" +#include "assert/assert.hpp" namespace Dawn { + class StateOwner; + template class StateProperty { private: StateOwner *owner; V value; + /** + * Method that is invoked every time that the value of this state property + * is updated. + * + * @param val Value that is to be used for this property. + */ void setInternal(V val) { if(val == this->value) return;// TODO: can I omit this? kinda bad tbh. assertNotNull(this->owner); @@ -44,6 +52,9 @@ namespace Dawn { return this->value; } + /** + * Destructor for StateProperty. + */ ~StateProperty() { this->owner->_statePropertyDestroyed(this); } diff --git a/src/dawntictactoe/scenes/TicTacToeScene.hpp b/src/dawntictactoe/scenes/TicTacToeScene.hpp index 40dc78d5..008cc5ad 100644 --- a/src/dawntictactoe/scenes/TicTacToeScene.hpp +++ b/src/dawntictactoe/scenes/TicTacToeScene.hpp @@ -42,10 +42,6 @@ namespace Dawn { } } } - - void onStateUpdate() override { - std::cout << "State Update Invoked" << std::endl; - } std::vector getRequiredAssets() override { auto assMan = &this->game->assetManager;