#pragma once // ------------------------------------------------------------------------------------------------ #include "Core/Privilege/Base.hpp" // ------------------------------------------------------------------------------------------------ namespace SqMod { /* ------------------------------------------------------------------------------------------------ * An individual unit/entity that inherits the privileges of a class/group and can * change their status without affecting other units and/or their associated class. * A unit cannot extend it's privileges to other entities. * Units cost more to query if they differ from their class but save memory in large numbers. * Each unit must have a unique numerical identifier within their associated manager. */ struct PvUnit { /* -------------------------------------------------------------------------------------------- * Strong and weak reference types. */ typedef std::shared_ptr< PvUnit > Ref; typedef std::weak_ptr< PvUnit > Ptr; /* -------------------------------------------------------------------------------------------- * Type of container used to store privilege units. */ typedef VecMap< PvIdentity, Ref, PvIdPred > List; /* -------------------------------------------------------------------------------------------- * User identifier associated with this unit instance. Always unique in the same manager! */ const SQInteger mID; /* -------------------------------------------------------------------------------------------- * Authority level associated with a particular unit. */ SQInteger mAuthority; /* -------------------------------------------------------------------------------------------- * A container with unique privilege status values associated with this unit. */ PvStatusList mPrivileges; /* -------------------------------------------------------------------------------------------- * Dedicated callback for privilege query event. */ Function mOnQuery; /* -------------------------------------------------------------------------------------------- * Dedicated callback for privilege gained event. */ Function mOnGained; /* -------------------------------------------------------------------------------------------- * Dedicated callback for privilege lost event. */ Function mOnLost; /* -------------------------------------------------------------------------------------------- * User tag associated with this instance. */ StackStrF mTag; /* -------------------------------------------------------------------------------------------- * User data associated with this instance. */ LightObj mData; /* -------------------------------------------------------------------------------------------- * Weak pointer to the associated class. Units always have an associated class! */ std::weak_ptr< PvClass > mClass; /* ------------------------------------------------------------------------------------------- * Default constructor. */ PvUnit(SQInteger id, std::weak_ptr< PvClass > cls) : mID(id) , mAuthority(0) , mPrivileges() , mOnQuery(), mOnGained(), mOnLost() , mTag(), mData() , mClass(std::move(cls)) { } /* ------------------------------------------------------------------------------------------- * Default constructor. */ PvUnit(SQInteger id, StackStrF && tag, std::weak_ptr< PvClass > cls) : mID(id) , mAuthority(0) , mPrivileges() , mOnQuery(), mOnGained(), mOnLost() , mTag(std::move(tag)), mData() , mClass(std::move(cls)) { } /* ------------------------------------------------------------------------------------------- * Copy constructor (disabled). */ PvUnit(const PvUnit & o) = delete; /* ------------------------------------------------------------------------------------------- * Move constructor (disabled). */ PvUnit(PvUnit && o) = delete; /* ------------------------------------------------------------------------------------------- * Destructor. */ ~PvUnit() = default; /* ------------------------------------------------------------------------------------------- * Copy assignment operator (disabled). */ PvUnit & operator = (const PvUnit & o) = delete; /* ------------------------------------------------------------------------------------------- * Move assignment operator (disabled). */ PvUnit & operator = (PvUnit && o) = delete; /* -------------------------------------------------------------------------------------------- * Modify the associated user tag. */ void SetTag(StackStrF & tag); /* -------------------------------------------------------------------------------------------- * Release all script resources. */ void Release(); /* -------------------------------------------------------------------------------------------- * Make sure the referenced parent class is valid. */ void ValidateClass() const { if (mClass.expired()) { STHROWF("Unit ({} : {}) has invalid class reference", mID, mTag.mPtr); } } /* -------------------------------------------------------------------------------------------- * Make sure the referenced parent class is valid and return a reference to it. */ SQMOD_NODISCARD PvClass & ValidClass() const { ValidateClass(); // Acquire a reference and return it return *(mClass.lock().get()); } /* -------------------------------------------------------------------------------------------- * Make sure the referenced manger is valid. */ void ValidateManager() const; /* -------------------------------------------------------------------------------------------- * Make sure the referenced manger is valid and return a reference to it. */ SQMOD_NODISCARD PvManager & ValidManager() const; /* -------------------------------------------------------------------------------------------- * Find out the callback that must be invoked to handle query events for a certain entry. */ SQMOD_NODISCARD const Function & GetOnQuery(SQInteger id) const; /* -------------------------------------------------------------------------------------------- * Find out the callback that must be invoked to handle gained events for a certain entry. */ SQMOD_NODISCARD const Function & GetOnGained(SQInteger id) const; /* -------------------------------------------------------------------------------------------- * Find out the callback that must be invoked to handle lost events for a certain entry. */ SQMOD_NODISCARD const Function & GetOnLost(SQInteger id) const; /* -------------------------------------------------------------------------------------------- * Retrieve the current value of an entry for this particular unit. */ SQMOD_NODISCARD SQInteger GetEntryValue(SQInteger id) const; /* -------------------------------------------------------------------------------------------- * Retrieve the inherited value of an entry for this particular unit. */ SQMOD_NODISCARD SQInteger GetInheritedEntryValue(SQInteger id) const; /* -------------------------------------------------------------------------------------------- * Perform the actions necessary to handle a privilege gain event. */ void DoGained(SQInteger id, SQInteger value) const; /* -------------------------------------------------------------------------------------------- * Perform the actions necessary to handle a privilege lost event. */ void DoLost(SQInteger id, SQInteger value) const; /* -------------------------------------------------------------------------------------------- * Perform the actions necessary to handle a privilege change event. */ void DoChanged(SQInteger id, bool status, SQInteger value) const; /* -------------------------------------------------------------------------------------------- * Assign a status value. Does not care if a parent (class or global) has the same status. * Later if the parent changes this status, we will keep having this status value. */ void AssignPrivilege(SQInteger id, SQInteger value); /* -------------------------------------------------------------------------------------------- * Remove a status value. If the specified status value is not assigned, nothing happens. */ void RemovePrivilege(SQInteger id); /* -------------------------------------------------------------------------------------------- * Assign a status value. If a parent (class or global) has the same value, nothing changes. * Same as AssignStatus but the status will not be enforced if we have it (inherited or not). */ void ModifyPrivilege(SQInteger id, SQInteger value); /* -------------------------------------------------------------------------------------------- * See AssignPrivilege(). */ void AssignPrivilege(StackStrF & tag, SQInteger value); /* -------------------------------------------------------------------------------------------- * See RemovePrivilege(). */ void RemovePrivilege(StackStrF & tag); /* -------------------------------------------------------------------------------------------- * See ModifyPrivilege(). */ void ModifyPrivilege(StackStrF & tag, SQInteger value); /* -------------------------------------------------------------------------------------------- * Remove all status values. Basically it reverts to the current class privileges. */ void RemoveAllPrivileges(); /* -------------------------------------------------------------------------------------------- * Assign a new class. */ void AssignClass(const std::shared_ptr< PvClass > & cls); /* -------------------------------------------------------------------------------------------- * Check if this unit has a certain privilege. */ SQMOD_NODISCARD bool Can(SQInteger id, SQInteger req) const; /* -------------------------------------------------------------------------------------------- * Invoke a given callback with every owned entry identifier. */ void EachEntryID(Object & ctx, Function & func) const; }; /* ------------------------------------------------------------------------------------------------ * Privilege unit wrapper. Mostly calls functions of the actual implementation. * Used to avoid having to involve hard script references that can persist. * Breaks away from usual formatting. */ struct SqPvUnit { PvUnit::Ptr mI; // -------------------------------------------------------------------------------------------- explicit SqPvUnit(PvUnit::Ptr i) : mI(std::move(i)) { } // NOLINT(modernize-pass-by-value) explicit SqPvUnit(const PvUnit::Ref & i) : mI(i) { } SqPvUnit(const SqPvUnit & o) = default; SqPvUnit(SqPvUnit && o) noexcept = default; ~SqPvUnit() = default; SqPvUnit & operator = (const SqPvUnit & o) = default; SqPvUnit & operator = (SqPvUnit && o) noexcept = default; // -------------------------------------------------------------------------------------------- void Validate() const { if (mI.expired()) STHROWF("Invalid unit reference"); } SQMOD_NODISCARD PvUnit & Valid() const { Validate(); return *(mI.lock().get()); } // -------------------------------------------------------------------------------------------- void ValidateCls() const { Validate(); if (mI.lock()->mClass.expired()) STHROWF("Invalid class reference"); } SQMOD_NODISCARD PvClass & ValidCls() const { ValidateCls(); return *(mI.lock()->mClass.lock().get()); } // -------------------------------------------------------------------------------------------- SQMOD_NODISCARD SQInteger GetID() const { return Valid().mID; } // -------------------------------------------------------------------------------------------- SQMOD_NODISCARD auto ToString() const { return Valid().mTag.mObj; } SQMOD_NODISCARD auto GetTag() const { return Valid().mTag.mObj; } void SetTag(StackStrF & tag) const { Valid().SetTag(tag); } SQMOD_NODISCARD SqPvUnit & ApplyTag(StackStrF & tag) { SetTag(tag); return *this; } SQMOD_NODISCARD LightObj & GetData() const { return Valid().mData; } void SetData(LightObj & data) const { Valid().mData = data; } // -------------------------------------------------------------------------------------------- void SetOnQuery(Function & func) const { Valid().mOnQuery = std::move(func); } void SetOnLost(Function & func) const { Valid().mOnLost = std::move(func); } void SetOnGained(Function & func) const { Valid().mOnGained = std::move(func); } // -------------------------------------------------------------------------------------------- SQMOD_NODISCARD SQInteger GetAuthority() const { return Valid().mAuthority; } void SetAuthority(SQInteger a) const { Valid().mAuthority = a; } // -------------------------------------------------------------------------------------------- SQMOD_NODISCARD LightObj GetClass() const; void SetClass(const SqPvClass & cls) const; // -------------------------------------------------------------------------------------------- SQMOD_NODISCARD LightObj GetManager() const; // -------------------------------------------------------------------------------------------- bool Can(LightObj & obj, SQInteger req) const; // -------------------------------------------------------------------------------------------- void AssignPrivilegeWithID(SQInteger id, SQInteger value) const { Valid().AssignPrivilege(id, value); } void AssignPrivilegeWithTag(StackStrF & tag, SQInteger value) const { Valid().AssignPrivilege(tag, value); } void RemovePrivilegeWithID(SQInteger id) const { Valid().RemovePrivilege(id); } void RemovePrivilegeWithTag(StackStrF & tag) const { Valid().RemovePrivilege(tag); } void ModifyPrivilegeWithID(SQInteger id, SQInteger value) const { Valid().ModifyPrivilege(id, value); } void ModifyPrivilegeWithTag(StackStrF & tag, SQInteger value) const { Valid().ModifyPrivilege(tag, value); } void RemoveAllPrivileges() const { Valid().RemoveAllPrivileges(); } // -------------------------------------------------------------------------------------------- void EachEntryID(Object & ctx, Function & func) const { return Valid().EachEntryID(ctx, func); } }; } // Namespace:: SqMod