mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-21 21:17:25 +00:00
Proposal for observers and deferred implementations (#1599)
This commit is contained in:
parent
84d7c65717
commit
fedd039e00
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
|
||||||
|
Loading…
Reference in New Issue
Block a user