mirror of
				https://github.com/DarkflameUniverse/DarkflameServer.git
				synced 2025-10-31 04:32:06 +00:00 
			
		
		
		
	Proposal for observers and deferred implementations
This commit is contained in:
		
							
								
								
									
										92
									
								
								dCommon/Implementation.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								dCommon/Implementation.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | |||||||
|  | #ifndef __IMPLEMENTATION_H__ | ||||||
|  | #define __IMPLEMENTATION_H__ | ||||||
|  |  | ||||||
|  | #include <functional> | ||||||
|  | #include <optional> | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief A way to defer the implementation of an action. | ||||||
|  |  *  | ||||||
|  |  * @tparam R The result of the action. | ||||||
|  |  * @tparam T The types of the arguments that the implementation requires. | ||||||
|  |  */ | ||||||
|  | template <typename R, typename... T> | ||||||
|  | class Implementation { | ||||||
|  | public: | ||||||
|  | 	typedef std::function<std::optional<R>(T...)> ImplementationFunction; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Sets the implementation of the action. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param implementation The implementation of the action. | ||||||
|  | 	 */ | ||||||
|  | 	void SetImplementation(const ImplementationFunction& implementation) { | ||||||
|  | 		this->implementation = implementation; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Clears the implementation of the action. | ||||||
|  | 	 */ | ||||||
|  | 	void ClearImplementation() { | ||||||
|  | 		implementation.reset(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Checks if the implementation is set. | ||||||
|  | 	 *  | ||||||
|  | 	 * @return true If the implementation is set. | ||||||
|  | 	 * @return false If the implementation is not set. | ||||||
|  | 	 */ | ||||||
|  | 	bool IsSet() const { | ||||||
|  | 		return implementation.has_value(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Executes the implementation if it is set. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param args The arguments to pass to the implementation. | ||||||
|  | 	 * @return std::optional<R> The optional result of the implementation. If the result is not set, it indicates that the default action should be taken. | ||||||
|  | 	 */ | ||||||
|  | 	std::optional<R> Execute(T... args) const { | ||||||
|  | 		return IsSet() ? implementation.value()(args...) : std::nullopt; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Exectues the implementation if it is set, otherwise returns a default value. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param args The arguments to pass to the implementation. | ||||||
|  | 	 * @param defaultValue The default value to return if the implementation is not set or should not be deferred. | ||||||
|  | 	 */ | ||||||
|  | 	R ExecuteWithDefault(T... args, const R& defaultValue) const { | ||||||
|  | 		return Execute(args...).value_or(defaultValue); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * = operator overload. | ||||||
|  | 	 */ | ||||||
|  | 	Implementation& operator=(const Implementation& other) { | ||||||
|  | 		implementation = other.implementation; | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * = operator overload. | ||||||
|  | 	 */ | ||||||
|  | 	Implementation& operator=(const ImplementationFunction& implementation) { | ||||||
|  | 		this->implementation = implementation; | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * () operator overload. | ||||||
|  | 	 */ | ||||||
|  | 	std::optional<R> operator()(T... args) { | ||||||
|  | 		return !IsSet() ? std::nullopt : implementation(args...); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	std::optional<ImplementationFunction> implementation; | ||||||
|  |  | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif  //!__IMPLEMENTATION_H__ | ||||||
							
								
								
									
										73
									
								
								dCommon/Observable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								dCommon/Observable.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | #ifndef __OBSERVABLE_H__ | ||||||
|  | #define __OBSERVABLE_H__ | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  | #include <functional> | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * @brief An event which can be observed by multiple observers. | ||||||
|  |  *  | ||||||
|  |  * @tparam T The types of the arguments to be passed to the observers. | ||||||
|  |  */ | ||||||
|  | template <typename... T> | ||||||
|  | class Observable { | ||||||
|  | public: | ||||||
|  | 	typedef std::function<void(T...)> Observer; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Adds an observer to the event. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param observer The observer to add. | ||||||
|  | 	 */ | ||||||
|  | 	void AddObserver(const Observer& observer) { | ||||||
|  | 		observers.push_back(observer); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Removes an observer from the event. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param observer The observer to remove. | ||||||
|  | 	 */ | ||||||
|  | 	void RemoveObserver(const Observer& observer) { | ||||||
|  | 		observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end()); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief Notifies all observers of the event. | ||||||
|  | 	 *  | ||||||
|  | 	 * @param args The arguments to pass to the observers. | ||||||
|  | 	 */ | ||||||
|  | 	void Notify(T... args) { | ||||||
|  | 		for (const auto& observer : observers) { | ||||||
|  | 			observer(args...); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * += operator overload. | ||||||
|  | 	 */ | ||||||
|  | 	Observable& operator+=(const Observer& observer) { | ||||||
|  | 		AddObserver(observer); | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * -= operator overload. | ||||||
|  | 	 */ | ||||||
|  | 	Observable& operator-=(const Observer& observer) { | ||||||
|  | 		RemoveObserver(observer); | ||||||
|  | 		return *this; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	/** | ||||||
|  | 	 * () operator overload. | ||||||
|  | 	 */ | ||||||
|  | 	void operator()(T... args) { | ||||||
|  | 		Notify(args...); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	std::vector<Observer> observers; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif  //!__OBSERVABLE_H__ | ||||||
| @@ -96,6 +96,8 @@ | |||||||
| #include "CDSkillBehaviorTable.h" | #include "CDSkillBehaviorTable.h" | ||||||
| #include "CDZoneTableTable.h" | #include "CDZoneTableTable.h" | ||||||
|  |  | ||||||
|  | Observable<Entity*, const PositionUpdate&> Entity::OnPlayerPositionUpdate; | ||||||
|  |  | ||||||
| Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) { | Entity::Entity(const LWOOBJID& objectID, EntityInfo info, User* parentUser, Entity* parentEntity) { | ||||||
| 	m_ObjectID = objectID; | 	m_ObjectID = objectID; | ||||||
| 	m_TemplateID = info.lot; | 	m_TemplateID = info.lot; | ||||||
| @@ -2133,6 +2135,8 @@ void Entity::ProcessPositionUpdate(PositionUpdate& update) { | |||||||
| 	Game::entityManager->QueueGhostUpdate(GetObjectID()); | 	Game::entityManager->QueueGhostUpdate(GetObjectID()); | ||||||
|  |  | ||||||
| 	if (updateChar) Game::entityManager->SerializeEntity(this); | 	if (updateChar) Game::entityManager->SerializeEntity(this); | ||||||
|  |  | ||||||
|  | 	OnPlayerPositionUpdate.Notify(this, update); | ||||||
| } | } | ||||||
|  |  | ||||||
| const SystemAddress& Entity::GetSystemAddress() const { | const SystemAddress& Entity::GetSystemAddress() const { | ||||||
|   | |||||||
| @@ -11,6 +11,7 @@ | |||||||
| #include "NiQuaternion.h" | #include "NiQuaternion.h" | ||||||
| #include "LDFFormat.h" | #include "LDFFormat.h" | ||||||
| #include "eKillType.h" | #include "eKillType.h" | ||||||
|  | #include "Observable.h" | ||||||
|  |  | ||||||
| namespace Loot { | namespace Loot { | ||||||
| 	class Info; | 	class Info; | ||||||
| @@ -299,6 +300,11 @@ public: | |||||||
| 	// Scale will only be communicated to the client when the construction packet is sent | 	// Scale will only be communicated to the client when the construction packet is sent | ||||||
| 	void SetScale(const float scale) { m_Scale = scale; }; | 	void SetScale(const float scale) { m_Scale = scale; }; | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	 * @brief The observable for player entity position updates. | ||||||
|  | 	 */ | ||||||
|  | 	static Observable<Entity*, const PositionUpdate&> OnPlayerPositionUpdate; | ||||||
|  | 	 | ||||||
| protected: | protected: | ||||||
| 	LWOOBJID m_ObjectID; | 	LWOOBJID m_ObjectID; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -38,6 +38,9 @@ | |||||||
|  |  | ||||||
| #include "CDComponentsRegistryTable.h" | #include "CDComponentsRegistryTable.h" | ||||||
|  |  | ||||||
|  | Implementation<bool, const Entity*> DestroyableComponent::IsEnemyImplentation; | ||||||
|  | Implementation<bool, const Entity*> DestroyableComponent::IsFriendImplentation; | ||||||
|  |  | ||||||
| DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { | DestroyableComponent::DestroyableComponent(Entity* parent) : Component(parent) { | ||||||
| 	m_iArmor = 0; | 	m_iArmor = 0; | ||||||
| 	m_fMaxArmor = 0.0f; | 	m_fMaxArmor = 0.0f; | ||||||
| @@ -418,6 +421,7 @@ void DestroyableComponent::AddFaction(const int32_t factionID, const bool ignore | |||||||
| } | } | ||||||
|  |  | ||||||
| bool DestroyableComponent::IsEnemy(const Entity* other) const { | bool DestroyableComponent::IsEnemy(const Entity* other) const { | ||||||
|  | 	if (IsEnemyImplentation.ExecuteWithDefault(other, false)) return true; | ||||||
| 	if (m_Parent->IsPlayer() && other->IsPlayer()) { | 	if (m_Parent->IsPlayer() && other->IsPlayer()) { | ||||||
| 		auto* thisCharacterComponent = m_Parent->GetComponent<CharacterComponent>(); | 		auto* thisCharacterComponent = m_Parent->GetComponent<CharacterComponent>(); | ||||||
| 		if (!thisCharacterComponent) return false; | 		if (!thisCharacterComponent) return false; | ||||||
| @@ -440,6 +444,7 @@ bool DestroyableComponent::IsEnemy(const Entity* other) const { | |||||||
| } | } | ||||||
|  |  | ||||||
| bool DestroyableComponent::IsFriend(const Entity* other) const { | bool DestroyableComponent::IsFriend(const Entity* other) const { | ||||||
|  | 	if (IsFriendImplentation.ExecuteWithDefault(other, false)) return true; | ||||||
| 	const auto* otherDestroyableComponent = other->GetComponent<DestroyableComponent>(); | 	const auto* otherDestroyableComponent = other->GetComponent<DestroyableComponent>(); | ||||||
| 	if (otherDestroyableComponent != nullptr) { | 	if (otherDestroyableComponent != nullptr) { | ||||||
| 		for (const auto enemyFaction : m_EnemyFactionIDs) { | 		for (const auto enemyFaction : m_EnemyFactionIDs) { | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
| #include "Entity.h" | #include "Entity.h" | ||||||
| #include "Component.h" | #include "Component.h" | ||||||
| #include "eReplicaComponentType.h" | #include "eReplicaComponentType.h" | ||||||
|  | #include "Implementation.h" | ||||||
|  |  | ||||||
| namespace CppScripts { | namespace CppScripts { | ||||||
| 	class Script; | 	class Script; | ||||||
| @@ -463,6 +464,9 @@ public: | |||||||
| 	// handle hardcode mode drops | 	// handle hardcode mode drops | ||||||
| 	void DoHardcoreModeDrops(const LWOOBJID source); | 	void DoHardcoreModeDrops(const LWOOBJID source); | ||||||
|  |  | ||||||
|  | 	static Implementation<bool, const Entity*> IsEnemyImplentation; | ||||||
|  | 	static Implementation<bool, const Entity*> IsFriendImplentation; | ||||||
|  |  | ||||||
| private: | private: | ||||||
| 	/** | 	/** | ||||||
| 	 * Whether or not the health should be serialized | 	 * Whether or not the health should be serialized | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 wincent
					wincent