1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-06-15 22:57:12 +02:00

First draft/prototype of built-in privilege management.

This commit is contained in:
Sandu Liviu Catalin
2021-02-05 13:32:37 +02:00
parent 6d30202bbd
commit 90597e4287
14 changed files with 3037 additions and 3 deletions

View File

@ -0,0 +1,9 @@
// ------------------------------------------------------------------------------------------------
#include "Core/Privilege/Base.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
} // Namespace:: SqMod

View File

@ -0,0 +1,105 @@
#pragma once
// ------------------------------------------------------------------------------------------------
#include "Core/Utility.hpp"
#include "Core/VecMap.hpp"
// ------------------------------------------------------------------------------------------------
#include <memory>
#include <utility>
#include <algorithm>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
struct SqPvUnit;
struct SqPvClass;
struct SqPvEntry;
// ------------------------------------------------------------------------------------------------
struct PvUnit;
struct PvClass;
struct PvEntry;
struct PvManager;
// ------------------------------------------------------------------------------------------------
typedef VecMap< SQInteger, SQInteger > PvStatusList;
/* ------------------------------------------------------------------------------------------------
* Used to represent unique identity for entries, units and classes.
*/
struct PvIdentity
{
/* --------------------------------------------------------------------------------------------
* Unique identifier. This must be unique for amongst similar identities.
*/
SQInteger mID{0};
/* --------------------------------------------------------------------------------------------
* Name hash. Optional cached value used when searching by name.
*/
size_t mHash{0};
/* -------------------------------------------------------------------------------------------
* Default constructor.
*/
constexpr PvIdentity() noexcept = default;
/* -------------------------------------------------------------------------------------------
* Identifier constructor.
*/
constexpr explicit PvIdentity(SQInteger id) noexcept
: mID(id), mHash(0)
{
}
/* -------------------------------------------------------------------------------------------
* Identifier and hash constructor.
*/
constexpr explicit PvIdentity(SQInteger id, size_t h) noexcept
: mID(id), mHash(h)
{
}
/* -------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
PvIdentity(const PvIdentity & o) noexcept = default;
/* -------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
PvIdentity(PvIdentity && o) noexcept = default;
/* -------------------------------------------------------------------------------------------
* Destructor.
*/
~PvIdentity() = default;
/* -------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
PvIdentity & operator = (const PvIdentity & o) noexcept = default;
/* -------------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
PvIdentity & operator = (PvIdentity && o) noexcept = default;
};
/* ------------------------------------------------------------------------------------------------
* Used as for VecMap to know when two elements are considered equal (the same).
*/
struct PvIdPred
{
/* --------------------------------------------------------------------------------------------
* Function call operator. Takes two identities and compares the `mID` member.
*/
bool operator() (const PvIdentity & a, const PvIdentity & b) const noexcept
{
return (a.mID == b.mID);
}
};
} // Namespace:: SqMod

View File

@ -0,0 +1,404 @@
// ------------------------------------------------------------------------------------------------
#include "Core/Privilege/Class.hpp"
#include "Core/Privilege.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMOD_DECL_TYPENAME(ClassTn, _SC("SqPrivilegeClass"))
// ------------------------------------------------------------------------------------------------
void PvClass::SetTag(StackStrF & tag)
{
mTag = std::move(tag);
// Hash the name and cache it (the name hash is cached in .mRes member variable)
mTag.CacheHash();
// Propagate this change to the manager as well
if (mManager)
{
mManager->UpdateClassHash(mID, static_cast< size_t >(mTag.mRes));
}
}
// ------------------------------------------------------------------------------------------------
void PvClass::Release()
{
mOnQuery.Release();
mOnGained.Release();
mOnLost.Release();
mTag.Release();
mData.Release();
}
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD PvManager & PvClass::ValidManager() const
{
ValidateManager();
// Return a reference it
return *mManager;
}
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD const Function & PvClass::GetOnQuery(SQInteger id) const
{
// Should we go for the one in the manager?
if (mOnQuery.IsNull())
{
return ValidManager().GetOnQuery(id);
}
// We're using our own
return mOnQuery;
}
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD const Function & PvClass::GetOnGained(SQInteger id) const
{
// Should we go for the one in the manager?
if (mOnGained.IsNull())
{
return ValidManager().GetOnGained(id);
}
// We're using our own
return mOnGained;
}
// ------------------------------------------------------------------------------------------------
SQMOD_NODISCARD const Function & PvClass::GetOnLost(SQInteger id) const
{
// Should we go for the one in the manager?
if (mOnLost.IsNull())
{
return ValidManager().GetOnLost(id);
}
// We're using our own
return mOnLost;
}
// ------------------------------------------------------------------------------------------------
SQInteger PvClass::GetEntryValue(SQInteger id) const
{
// Look for the specified status value
auto itr = mPrivileges.find(id);
// Should we go for the one in the parent?
if (itr == mPrivileges.end())
{
// Should we go for the default one?
if (mParent.expired())
{
return ValidManager().GetEntryValue(id);
}
// We have a valid parent
return ValidParent().GetEntryValue(id);
}
// Return the associated value
return itr->second;
}
// ------------------------------------------------------------------------------------------------
SQInteger PvClass::GetInheritedEntryValue(SQInteger id) const
{
// Should we go for the default one?
if (mParent.expired())
{
return ValidManager().GetEntryValue(id);
}
// We have a valid parent
return ValidParent().GetEntryValue(id);
}
// ------------------------------------------------------------------------------------------------
void PvClass::DoGained(SQInteger id, SQInteger value) const
{
// Function to be called when a privilege is gained
const Function & gained = GetOnGained(id);
// Is there someone interested in this result?
if (!gained.IsNull())
{
gained.Execute(id, value);
}
}
// ------------------------------------------------------------------------------------------------
void PvClass::DoLost(SQInteger id, SQInteger value) const
{
// Function to be called when a privilege is lost
const Function & lost = GetOnLost(id);
// Is there someone interested in this result?
if (!lost.IsNull())
{
lost.Execute(id, value);
}
}
// ------------------------------------------------------------------------------------------------
void PvClass::DoChanged(SQInteger id, bool status, SQInteger value) const
{
// Was this considered an upgrade?
if (status)
{
DoGained(id, value);
}
else
{
DoLost(id, value);
}
}
// ------------------------------------------------------------------------------------------------
void PvClass::AssignStatus(SQInteger id, SQInteger value)
{
// Find the current status of this entry
SQInteger current = GetEntryValue(id);
// Retrieve the associated entry
PvEntry & entry = ValidManager().ValidEntry(id);
// Is there someone that can identify this change?
if (!entry.mOnModify.IsNull())
{
LightObj r = entry.mOnModify.Eval(current, value);
// Was this considered a change?
if (!r.IsNull())
{
DoChanged(id, r.Cast< bool >(), value);
}
}
// Either waiy, we are setting this value
mPrivileges[id] = value;
}
// ------------------------------------------------------------------------------------------------
void PvClass::RemoveStatus(SQInteger id)
{
// Look for the status of this value
auto itr = mPrivileges.find(id);
// Do we even have this status?
if (itr == mPrivileges.end())
{
return; // Nothing to remove!
}
// Find the inherited status of this entry
SQInteger inherited = GetInheritedEntryValue(id);
// Get the current status of this entry
SQInteger current = itr->second;
// Erase this status value
mPrivileges.erase(itr);
// Retrieve the associated entry
PvEntry & entry = ValidManager().ValidEntry(id);
// Is there someone that can identify this change?
if (!entry.mOnModify.IsNull())
{
LightObj r = entry.mOnModify.Eval(current, inherited);
// Was this considered a change?
if (!r.IsNull())
{
DoChanged(id, r.Cast< bool >(), current);
}
}
}
// ------------------------------------------------------------------------------------------------
void PvClass::ModifyStatus(SQInteger id, SQInteger value)
{
// Find the current status of this entry
SQInteger current = GetEntryValue(id);
// If they are exactly the same
if (value == current)
{
return; // Just do nothing
}
// Retrieve the associated entry
PvEntry & entry = ValidManager().ValidEntry(id);
// Is there someone that can identify this change?
if (!entry.mOnModify.IsNull())
{
LightObj r = entry.mOnModify.Eval(current, value);
// Was this considered a change?
if (!r.IsNull())
{
DoChanged(id, r.Cast< bool >(), value);
// Use this value now as well
mPrivileges[id] = value;
}
}
else
{
// By default we use > comparison to decide upgrades
DoChanged(id, value > current, value);
// Use this value now
mPrivileges[id] = value;
}
}
// ------------------------------------------------------------------------------------------------
void PvClass::AssignParent(const Ref & parent)
{
// Do we have a parent?
if (mParent.expired())
{
// Assign the specified class
mParent = parent;
// Propagate changes
ValidManager().PropagateParentAssign(*this, parent);
}
// Are they the same?
else if (mParent.lock() != parent)
{
// Assign the specified class
mParent = parent;
// Propagate changes
ValidManager().PropagateParentChange(*this, parent);
}
}
// ------------------------------------------------------------------------------------------------
bool PvClass::Can(SQInteger id) const
{
// Retrieve the function responsible for the query event
const Function & query = GetOnQuery(id);
// Is there someone that can arbitrate this request?
if (!query.IsNull())
{
// Get the current status of the specified entry
SQInteger current = GetEntryValue(id);
// Attempt arbitration
LightObj r = query.Eval(current);
// If NULL or false the request was denied
if (!r.IsNull() && r.Cast< bool >())
{
return true; // Request allowed
}
}
// Request failed, no arbitration
return false;
}
// ------------------------------------------------------------------------------------------------
LightObj PvClass::GetUnitWithID(SQInteger id)
{
for (const auto & u : mUnits)
{
if (u.first.mID == id)
{
return LightObj(SqTypeIdentity< SqPvUnit >{}, SqVM(), u.second);
}
}
// Not found
STHROWF("Unit ({}) does not inherit from this class", id);
SQ_UNREACHABLE
}
// ------------------------------------------------------------------------------------------------
LightObj PvClass::GetUnitWithTag(StackStrF & tag)
{
const size_t h = tag.ToHash();
for (const auto & u : mUnits)
{
if (u.first.mHash == h)
{
return LightObj(SqTypeIdentity< SqPvUnit >{}, SqVM(), u.second);
}
}
// Not found
STHROWF("Unit ({}) does not inherit from this class", tag.mPtr);
SQ_UNREACHABLE
}
// ------------------------------------------------------------------------------------------------
bool PvClass::HaveUnitWithID(SQInteger id)
{
for (const auto & u : mUnits) // NOLINT(readability-use-anyofallof)
{
if (u.first.mID == id)
{
return true;
}
}
// Not found
return false;
}
// ------------------------------------------------------------------------------------------------
bool PvClass::HaveUnitWithTag(StackStrF & tag)
{
const size_t h = tag.ToHash();
for (const auto & u : mUnits) // NOLINT(readability-use-anyofallof)
{
if (u.first.mHash == h)
{
return true;
}
}
// Not found
return false;
}
// ================================================================================================
bool SqPvClass::Can(LightObj & obj) const
{
// Entry ID?
if (obj.GetType() == OT_INTEGER)
{
return Valid().Can(obj.Cast< SQInteger >());
}
// Entry tag?
else if (obj.GetType() == OT_STRING)
{
Var< LightObj >::push(SqVM(), obj);
// Tag string
StackStrF tag(SqVM(), -1);
// Attempt extraction
if (SQ_FAILED(tag.Proc(false)))
{
// Restore the stack first
sq_poptop(SqVM());
// Now the exception
STHROWF("Unable to extract tag string");
}
// Restore the stack
sq_poptop(SqVM());
// Reference the instance
PvClass & c = Valid();
// Generate and cache the hash
tag.CacheHash();
// Forward request
return c.Can(c.ValidManager().GetValidEntryWithTag(tag)->mID);
}
// Entry instance?
else if (obj.GetType() == OT_INSTANCE && obj.GetTypeTag() == StaticClassTypeTag< SqPvEntry >::Get())
{
return Valid().Can(obj.CastI< SqPvEntry >()->Valid().mID);
}
STHROWF("Unknown or unsupported entry identification type (%s)", SqTypeName(obj.GetType()));
SQ_UNREACHABLE
}
// ================================================================================================
void Register_Privilege_Class(HSQUIRRELVM vm, Table & ns)
{
ns.Bind(_SC("Class"),
Class< SqPvClass, NoConstructor< SqPvClass > >(vm, ClassTn::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &ClassTn::Fn)
.Func(_SC("_tostring"), &SqPvClass::ToString)
// Core Properties
.Prop(_SC("ID"), &SqPvClass::GetID)
.Prop(_SC("Tag"), &SqPvClass::GetTag, &SqPvClass::SetTag)
.Prop(_SC("Data"), &SqPvClass::GetData, &SqPvClass::SetData)
.Prop(_SC("Parent"), &SqPvClass::GetParent, &SqPvClass::SetParent)
.Prop(_SC("Manager"), &SqPvClass::GetManager)
// Core Methods
.FmtFunc(_SC("SetTag"), &SqPvClass::ApplyTag)
.CbFunc(_SC("OnQuery"), &SqPvClass::SetOnQuery)
.CbFunc(_SC("OnLost"), &SqPvClass::SetOnLost)
.CbFunc(_SC("OnGained"), &SqPvClass::SetOnGained)
// Member Methods
.Func(_SC("Can"), &SqPvUnit::Can)
.Func(_SC("GetUnit"), &SqPvClass::GetUnitWithID)
.FmtFunc(_SC("GetUnitWithTag"), &SqPvClass::GetUnitWithTag)
.Func(_SC("HaveUnit"), &SqPvClass::HaveUnitWithID)
.FmtFunc(_SC("HaveUnitWithTag"), &SqPvClass::HaveUnitWithTag)
// Member Overloads
);
}
} // Namespace:: SqMod

View File

@ -0,0 +1,335 @@
#pragma once
// ------------------------------------------------------------------------------------------------
#include "Core/Privilege/Unit.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* An individual class/group that can optionally inherit the privileges of another and can
* change their status to affect their children but not their parent class.
* A class can extend it's privileges to units and/or other classes.
* These cost less to query but use more memory because they're fewer and they preallocate it.
* Each class must have a unique numerical identifier within their associated manager.
*/
struct PvClass
{
/* --------------------------------------------------------------------------------------------
* Strong and weak reference types.
*/
typedef std::shared_ptr< PvClass > Ref;
typedef std::weak_ptr< PvClass > Ptr;
/* --------------------------------------------------------------------------------------------
* Type of container used to store privilege classes.
*/
typedef VecMap< PvIdentity, Ref, PvIdPred > List;
/* --------------------------------------------------------------------------------------------
* User identifier associated with this class instance. Always unique in the same manager!
*/
const SQInteger mID;
/* --------------------------------------------------------------------------------------------
* The parent class from which we are inheriting privileges, if any.
*/
Ptr mParent;
/* --------------------------------------------------------------------------------------------
* A container with unique privilege status values associated with this class.
*/
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;
/* --------------------------------------------------------------------------------------------
* Container that stores all the associated units.
*/
PvUnit::List mUnits;
/* --------------------------------------------------------------------------------------------
* User tag associated with this instance.
*/
StackStrF mTag;
/* --------------------------------------------------------------------------------------------
* User data associated with this instance.
*/
LightObj mData;
/* --------------------------------------------------------------------------------------------
* Pointer to the associated manager. Should always be present.
*
*/
PvManager * mManager;
/* -------------------------------------------------------------------------------------------
* Default constructor.
*/
PvClass(SQInteger id, PvManager * mgr)
: mID(id)
, mParent()
, mPrivileges()
, mOnQuery(), mOnGained(), mOnLost()
, mUnits()
, mTag(), mData()
, mManager(mgr)
{
}
/* -------------------------------------------------------------------------------------------
* Default constructor.
*/
PvClass(SQInteger id, StackStrF && tag, PvManager * mgr)
: mID(id)
, mParent()
, mPrivileges()
, mOnQuery(), mOnGained(), mOnLost()
, mUnits()
, mTag(std::move(tag)), mData()
, mManager(mgr)
{
}
/* -------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
PvClass(const PvClass & o) = delete;
/* -------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
PvClass(PvClass && o) = delete;
/* -------------------------------------------------------------------------------------------
* Destructor.
*/
~PvClass() = default;
/* -------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
PvClass & operator = (const PvClass & o) = delete;
/* -------------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
PvClass & operator = (PvClass && o) = delete;
/* --------------------------------------------------------------------------------------------
* Modify the associated user tag.
*/
void SetTag(StackStrF & tag);
/* --------------------------------------------------------------------------------------------
* Release all script resources. Recursively forward request.
*/
void Release();
/* --------------------------------------------------------------------------------------------
* Make sure the referenced parent class is valid.
*/
void ValidateParent() const
{
if (mParent.expired())
{
STHROWF("Class ({} : {}) has invalid parent class reference", mID, mTag.mPtr);
}
}
/* --------------------------------------------------------------------------------------------
* Make sure the referenced parent class is valid and return a reference to it.
*/
SQMOD_NODISCARD PvClass & ValidParent() const
{
ValidateParent();
// Acquire a reference and return it
return *(mParent.lock().get());
}
/* --------------------------------------------------------------------------------------------
* Make sure the referenced manager is valid.
*/
void ValidateManager() const
{
if (!mManager)
{
STHROWF("Class ({} : {}) has invalid manager reference", mID, mTag.mPtr);
}
}
/* --------------------------------------------------------------------------------------------
* 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 class.
*/
SQMOD_NODISCARD SQInteger GetEntryValue(SQInteger id) const;
/* --------------------------------------------------------------------------------------------
* Retrieve the inherited value of an entry for this particular class.
*/
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 AssignStatus(SQInteger id, SQInteger value);
/* --------------------------------------------------------------------------------------------
* Remove a status value. If the specified status value is not assigned, nothing happens.
*/
void RemoveStatus(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 ModifyStatus(SQInteger id, SQInteger value);
/* --------------------------------------------------------------------------------------------
* Change the parent class.
*/
void AssignParent(const Ref & parent);
/* --------------------------------------------------------------------------------------------
* Check if this class has a certain privilege.
*/
SQMOD_NODISCARD bool Can(SQInteger id) const;
/* --------------------------------------------------------------------------------------------
* See if a unit with a certain identifier inherits this class.
*/
SQMOD_NODISCARD LightObj GetUnitWithID(SQInteger id);
/* --------------------------------------------------------------------------------------------
* See if a unit with a certain tag inherits this class.
*/
SQMOD_NODISCARD LightObj GetUnitWithTag(StackStrF & tag);
/* --------------------------------------------------------------------------------------------
* See if a unit with a certain identifier inherits this class.
*/
bool HaveUnitWithID(SQInteger id);
/* --------------------------------------------------------------------------------------------
* See if a unit with a certain tag inherits this class.
*/
bool HaveUnitWithTag(StackStrF & tag);
/* --------------------------------------------------------------------------------------------
* Update the hash of the specified unit.
*/
void UpdateUnitHash(SQInteger id, size_t hash)
{
auto itr = mUnits.find(PvIdentity(id));
// Only update if it exists
if (itr != mUnits.end())
{
itr->first.mHash = hash;
}
}
};
/* ------------------------------------------------------------------------------------------------
* Privilege class 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 SqPvClass
{
PvClass::Ptr mI;
// --------------------------------------------------------------------------------------------
explicit SqPvClass(PvClass::Ptr i) : mI(std::move(i)) { } // NOLINT(modernize-pass-by-value)
explicit SqPvClass(const PvClass::Ref & i) : mI(i) { }
SqPvClass(const SqPvClass & o) = default;
SqPvClass(SqPvClass && o) noexcept = default;
~SqPvClass() = default;
SqPvClass & operator = (const SqPvClass & o) = default;
SqPvClass & operator = (SqPvClass && o) noexcept = default;
// --------------------------------------------------------------------------------------------
void Validate() const { if (mI.expired()) STHROWF("Invalid unit reference"); }
SQMOD_NODISCARD PvClass & Valid() const { Validate(); return *(mI.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 SqPvClass & 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 LightObj GetManager() const { return LightObj(Valid().mManager); }
// --------------------------------------------------------------------------------------------
SQMOD_NODISCARD LightObj GetParent() const
{
return LightObj(SqTypeIdentity< SqPvClass >{}, SqVM(), Valid().mParent);
}
void SetParent(const SqPvClass & cls) const
{
Validate();
cls.Validate();
mI.lock()->AssignParent(cls.mI.lock());
}
// --------------------------------------------------------------------------------------------
bool Can(LightObj & obj) const;
// --------------------------------------------------------------------------------------------
SQMOD_NODISCARD LightObj GetUnitWithID(SQInteger id) const { return Valid().GetUnitWithID(id); }
SQMOD_NODISCARD LightObj GetUnitWithTag(StackStrF & tag) const { return Valid().GetUnitWithTag(tag); }
SQMOD_NODISCARD bool HaveUnitWithID(SQInteger id) const { return Valid().HaveUnitWithID(id); }
SQMOD_NODISCARD bool HaveUnitWithTag(StackStrF & tag) const { return Valid().HaveUnitWithTag(tag); }
};
} // Namespace:: SqMod

View File

@ -0,0 +1,66 @@
// ------------------------------------------------------------------------------------------------
#include "Core/Privilege/Entry.hpp"
#include "Core/Privilege.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMOD_DECL_TYPENAME(EntryTn, _SC("SqPrivilegeEntry"))
// ------------------------------------------------------------------------------------------------
void PvEntry::SetTag(StackStrF & tag)
{
mTag = std::move(tag);
// Hash the name and cache it (the name hash is cached in .mRes member variable)
mTag.CacheHash();
// Propagate this change to the manager as well
if (mManager)
{
mManager->UpdateEntryHash(mID, static_cast< size_t >(mTag.mRes));
}
}
// ------------------------------------------------------------------------------------------------
void PvEntry::Release()
{
mTag.Release();
mOnQuery.Release();
mOnModify.Release();
mOnGained.Release();
mOnLost.Release();
mData.Release();
mBrief.Release();
mInfo.Release();
}
// ================================================================================================
void Register_Privilege_Entry(HSQUIRRELVM vm, Table & ns)
{
ns.Bind(_SC("Entry"),
Class< SqPvEntry, NoConstructor< SqPvEntry > >(vm, EntryTn::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &EntryTn::Fn)
.Func(_SC("_tostring"), &SqPvEntry::ToString)
// Core Properties
.Prop(_SC("ID"), &SqPvEntry::GetID)
.Prop(_SC("Tag"), &SqPvEntry::GetTag, &SqPvEntry::SetTag)
.Prop(_SC("Data"), &SqPvEntry::GetData, &SqPvEntry::SetData)
.Prop(_SC("Manager"), &SqPvEntry::GetManager)
.Prop(_SC("Brief"), &SqPvEntry::GetBrief, &SqPvEntry::SetBrief)
.Prop(_SC("Info"), &SqPvEntry::GetInfo, &SqPvEntry::SetInfo)
.Prop(_SC("Default"), &SqPvEntry::GetDefault, &SqPvEntry::SetDefault)
// Core Methods
.FmtFunc(_SC("SetTag"), &SqPvEntry::ApplyTag)
.CbFunc(_SC("OnQuery"), &SqPvEntry::SetOnQuery)
.CbFunc(_SC("OnModify"), &SqPvEntry::SetOnModify)
.CbFunc(_SC("OnLost"), &SqPvEntry::SetOnLost)
.CbFunc(_SC("OnGained"), &SqPvEntry::SetOnGained)
// Member Methods
.FmtFunc(_SC("SetBrief"), &SqPvEntry::ApplyBrief)
.FmtFunc(_SC("SetInfo"), &SqPvEntry::ApplyInfo)
// Raw functions
);
}
} // Namespace:: SqMod

View File

@ -0,0 +1,188 @@
#pragma once
// ------------------------------------------------------------------------------------------------
#include "Core/Privilege/Base.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
/* ------------------------------------------------------------------------------------------------
* An entry represents a privilege that a class or unit can can have.
* Each entry must have a unique numerical identifier within their associated manager.
*/
struct PvEntry
{
/* --------------------------------------------------------------------------------------------
* Strong and weak reference types.
*/
typedef std::shared_ptr< PvEntry > Ref;
typedef std::weak_ptr< PvEntry > Ptr;
/* --------------------------------------------------------------------------------------------
* Type of container used to store privilege entries.
*/
typedef VecMap< PvIdentity, Ref, PvIdPred > List;
/* --------------------------------------------------------------------------------------------
* User identifier associated with this entry instance. Always unique in the same manager!
*/
const SQInteger mID;
/* --------------------------------------------------------------------------------------------
* User tag associated with this instance.
*/
StackStrF mTag;
/* --------------------------------------------------------------------------------------------
* Dedicated callback for privilege query event.
*/
Function mOnQuery;
/* --------------------------------------------------------------------------------------------
* Dedicated callback for privilege gained event.
*/
Function mOnGained;
/* --------------------------------------------------------------------------------------------
* Dedicated callback for privilege modify event.
*/
Function mOnModify;
/* --------------------------------------------------------------------------------------------
* Dedicated callback for privilege lost event.
*/
Function mOnLost;
/* --------------------------------------------------------------------------------------------
* User data associated with this instance.
*/
LightObj mData;
/* --------------------------------------------------------------------------------------------
* Brief information about the privilege.
*/
StackStrF mBrief;
/* --------------------------------------------------------------------------------------------
* Detailed information about the privilege.
*/
StackStrF mInfo;
/* --------------------------------------------------------------------------------------------
* Implicit privilege status value.
*/
SQInteger mDefault;
/* --------------------------------------------------------------------------------------------
* Pointer to the associated manager. Should always be present.
*/
PvManager * mManager;
/* -------------------------------------------------------------------------------------------
* Default constructor.
*/
PvEntry(SQInteger id, PvManager * mgr)
: mID(id), mTag()
, mOnQuery(), mOnModify(), mOnGained(), mOnLost()
, mData(), mBrief(), mInfo(), mDefault()
, mManager(mgr)
{
}
/* -------------------------------------------------------------------------------------------
* Default constructor.
*/
PvEntry(SQInteger id, StackStrF && tag, PvManager * mgr)
: mID(id), mTag(std::move(tag))
, mOnQuery(), mOnModify(), mOnGained(), mOnLost()
, mData(), mBrief(), mInfo(), mDefault()
, mManager(mgr)
{
}
/* -------------------------------------------------------------------------------------------
* Copy constructor (disabled).
*/
PvEntry(const PvEntry & o) = delete;
/* -------------------------------------------------------------------------------------------
* Move constructor (disabled).
*/
PvEntry(PvEntry && o) = delete;
/* -------------------------------------------------------------------------------------------
* Destructor.
*/
~PvEntry() = default;
/* -------------------------------------------------------------------------------------------
* Copy assignment operator (disabled).
*/
PvEntry & operator = (const PvEntry & o) = delete;
/* -------------------------------------------------------------------------------------------
* Move assignment operator (disabled).
*/
PvEntry & operator = (PvEntry && o) = delete;
/* --------------------------------------------------------------------------------------------
* Modify the associated user tag.
*/
void SetTag(StackStrF & tag);
/* --------------------------------------------------------------------------------------------
* Release all script resources.
*/
void Release();
};
/* ------------------------------------------------------------------------------------------------
* Privilege entry 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 SqPvEntry
{
PvEntry::Ptr mI;
// --------------------------------------------------------------------------------------------
explicit SqPvEntry(PvEntry::Ptr i) : mI(std::move(i)) { } // NOLINT(modernize-pass-by-value)
explicit SqPvEntry(const PvEntry::Ref & i) : mI(i) { }
SqPvEntry(const SqPvEntry & o) = default;
SqPvEntry(SqPvEntry && o) noexcept = default;
~SqPvEntry() = default;
SqPvEntry & operator = (const SqPvEntry & o) = default;
SqPvEntry & operator = (SqPvEntry && o) noexcept = default;
// --------------------------------------------------------------------------------------------
void Validate() const { if (mI.expired()) STHROWF("Invalid unit reference"); }
SQMOD_NODISCARD PvEntry & Valid() const { Validate(); return *(mI.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 SqPvEntry & 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 SetOnModify(Function & func) const { Valid().mOnModify = 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 auto GetBrief() const { return Valid().mBrief.mObj; }
void SetBrief(StackStrF & str) const { Valid().mBrief = std::move(str); }
SQMOD_NODISCARD SqPvEntry & ApplyBrief(StackStrF & str) { SetBrief(str); return *this; }
// --------------------------------------------------------------------------------------------
SQMOD_NODISCARD auto GetInfo() const { return Valid().mInfo.mObj; }
void SetInfo(StackStrF & str) const { Valid().mInfo = std::move(str); }
SQMOD_NODISCARD SqPvEntry & ApplyInfo(StackStrF & str) { SetInfo(str); return *this; }
// --------------------------------------------------------------------------------------------
SQMOD_NODISCARD SQInteger GetDefault() const { return Valid().mDefault; }
void SetDefault(SQInteger value) const { Valid().mDefault = value; }
// --------------------------------------------------------------------------------------------
SQMOD_NODISCARD LightObj GetManager() const { return LightObj(Valid().mManager); }
};
} // Namespace:: SqMod

View File

@ -0,0 +1,370 @@
// ------------------------------------------------------------------------------------------------
#include "Core/Privilege/Unit.hpp"
#include "Core/Privilege/Entry.hpp"
#include "Core/Privilege/Class.hpp"
#include "Core/Privilege.hpp"
// ------------------------------------------------------------------------------------------------
namespace SqMod {
// ------------------------------------------------------------------------------------------------
SQMOD_DECL_TYPENAME(UnitTn, _SC("SqPrivilegeUnit"))
// ------------------------------------------------------------------------------------------------
void PvUnit::SetTag(StackStrF & tag)
{
mTag = std::move(tag);
// Hash the name and cache it (the name hash is cached in .mRes member variable)
mTag.CacheHash();
// Do we still belong to a class? (should always be. but always check)
if (!mClass.expired())
{
auto p = mClass.lock();
// Propagate this change to the class as well
p->UpdateUnitHash(mID, static_cast< size_t >(mTag.mRes));
// Propagate this change to the manager as well
if (p->mManager)
{
p->mManager->UpdateUnitHash(mID, static_cast< size_t >(mTag.mRes));
}
}
}
// ------------------------------------------------------------------------------------------------
void PvUnit::Release()
{
mOnQuery.Release();
mOnGained.Release();
mOnLost.Release();
mTag.Release();
mData.Release();
}
// ------------------------------------------------------------------------------------------------
void PvUnit::ValidateManager() const
{
ValidateClass();
// Validate the manager through the class
if (!(mClass.lock()->mManager))
{
STHROWF("Unit ({} : {}) has invalid manager reference", mID, mTag.mPtr);
}
}
// ------------------------------------------------------------------------------------------------
PvManager & PvUnit::ValidManager() const
{
ValidateClass();
// Retrieve the manager pointer (lock only once)
PvManager * ptr = mClass.lock()->mManager;
// Validate the manager through the class
if (!ptr)
{
STHROWF("Unit ({} : {}) has invalid manager reference", mID, mTag.mPtr);
}
// Acquire a reference and return it
return *ptr;
}
// ------------------------------------------------------------------------------------------------
const Function & PvUnit::GetOnQuery(SQInteger id) const
{
// Should we go for the one in the class?
if (mOnQuery.IsNull())
{
return ValidClass().GetOnQuery(id);
}
// We're using our own
return mOnQuery;
}
// ------------------------------------------------------------------------------------------------
const Function & PvUnit::GetOnGained(SQInteger id) const
{
// Should we go for the one in the class?
if (mOnGained.IsNull())
{
return ValidClass().GetOnGained(id);
}
// We're using our own
return mOnGained;
}
// ------------------------------------------------------------------------------------------------
const Function & PvUnit::GetOnLost(SQInteger id) const
{
// Should we go for the one in the class?
if (mOnLost.IsNull())
{
return ValidClass().GetOnLost(id);
}
// We're using our own
return mOnLost;
}
// ------------------------------------------------------------------------------------------------
SQInteger PvUnit::GetEntryValue(SQInteger id) const
{
// Look for the specified status value
auto itr = mPrivileges.find(id);
// Should we go for the one in the parent?
if (itr == mPrivileges.end())
{
return ValidClass().GetEntryValue(id);
}
// Return the associated value
return itr->second;
}
// ------------------------------------------------------------------------------------------------
SQInteger PvUnit::GetInheritedEntryValue(SQInteger id) const
{
return ValidClass().GetEntryValue(id);
}
// ------------------------------------------------------------------------------------------------
void PvUnit::DoGained(SQInteger id, SQInteger value) const
{
// Function to be called when a privilege is gained
const Function & gained = GetOnGained(id);
// Is there someone interested in this result?
if (!gained.IsNull())
{
gained.Execute(id, value);
}
}
// ------------------------------------------------------------------------------------------------
void PvUnit::DoLost(SQInteger id, SQInteger value) const
{
// Function to be called when a privilege is lost
const Function & lost = GetOnLost(id);
// Is there someone interested in this result?
if (!lost.IsNull())
{
lost.Execute(id, value);
}
}
// ------------------------------------------------------------------------------------------------
void PvUnit::DoChanged(SQInteger id, bool status, SQInteger value) const
{
// Was this considered an upgrade?
if (status)
{
DoGained(id, value);
}
else
{
DoLost(id, value);
}
}
// ------------------------------------------------------------------------------------------------
void PvUnit::AssignStatus(SQInteger id, SQInteger value)
{
// Find the current status of this entry
SQInteger current = GetEntryValue(id);
// Retrieve the associated entry
PvEntry & entry = ValidManager().ValidEntry(id);
// Is there someone that can identify this change?
if (!entry.mOnModify.IsNull())
{
LightObj r = entry.mOnModify.Eval(current, value);
// Was this considered a change?
if (!r.IsNull())
{
DoChanged(id, r.Cast< bool >(), value);
}
}
// Either way, we are setting this value
mPrivileges[id] = value;
}
// ------------------------------------------------------------------------------------------------
void PvUnit::RemoveStatus(SQInteger id)
{
// Look for the status of this value
auto itr = mPrivileges.find(id);
// Do we even have this status?
if (itr == mPrivileges.end())
{
return; // Nothing to remove!
}
// Find the inherited status of this entry
SQInteger inherited = GetInheritedEntryValue(id);
// Get the current status of this entry
SQInteger current = itr->second;
// Erase this status value
mPrivileges.erase(itr);
// Retrieve the associated entry
PvEntry & entry = ValidManager().ValidEntry(id);
// Is there someone that can identify this change?
if (!entry.mOnModify.IsNull())
{
LightObj r = entry.mOnModify.Eval(current, inherited);
// Was this considered a change?
if (!r.IsNull())
{
DoChanged(id, r.Cast< bool >(), current);
}
}
}
// ------------------------------------------------------------------------------------------------
void PvUnit::ModifyStatus(SQInteger id, SQInteger value)
{
// Find the current status of this entry
SQInteger current = GetEntryValue(id);
// If they are exactly the same
if (value == current)
{
return; // Just do nothing
}
// Retrieve the associated entry
PvEntry & entry = ValidManager().ValidEntry(id);
// Is there someone that can identify this change?
if (!entry.mOnModify.IsNull())
{
LightObj r = entry.mOnModify.Eval(current, value);
// Was this considered a change?
if (!r.IsNull())
{
DoChanged(id, r.Cast< bool >(), value);
// Use this value now as well
mPrivileges[id] = value;
}
}
else
{
// By default we use > comparison to decide upgrades
DoChanged(id, value > current, value);
// Use this value now
mPrivileges[id] = value;
}
}
// ------------------------------------------------------------------------------------------------
void PvUnit::AssignClass(const std::shared_ptr< PvClass > & cls)
{
// Make sure we have a valid class
ValidateClass();
// Get a strong reference to the current class
PvClass::Ref current = mClass.lock();
// Are they the same?
if (current == cls)
{
return; // Nothing will change
}
// Assign this class
mClass = cls;
// Propagate changes
ValidManager().PropagateClassChange(*this, cls);
}
// ------------------------------------------------------------------------------------------------
bool PvUnit::Can(SQInteger id) const
{
// Retrieve the function responsible for the query event
const Function & query = GetOnQuery(id);
// Is there someone that can arbitrate this request?
if (!query.IsNull())
{
// Get the current status of the specified entry
SQInteger current = GetEntryValue(id);
// Attempt arbitration
LightObj r = query.Eval(current);
// If NULL or false the request was denied
if (!r.IsNull() && r.Cast< bool >())
{
return true; // Request allowed
}
}
// Request failed, no arbitration
return false;
}
// ================================================================================================
LightObj SqPvUnit::GetClass() const
{
return LightObj(SqTypeIdentity< SqPvClass >{}, SqVM(), Valid().mClass);
}
// ------------------------------------------------------------------------------------------------
inline void SqPvUnit::SetClass(const SqPvClass & cls) const
{
Validate();
cls.Validate();
mI.lock()->AssignClass(cls.mI.lock());
}
// ------------------------------------------------------------------------------------------------
LightObj SqPvUnit::GetManager() const { return LightObj(ValidCls().mManager); }
// ------------------------------------------------------------------------------------------------
bool SqPvUnit::Can(LightObj & obj) const
{
// Entry ID?
if (obj.GetType() == OT_INTEGER)
{
return Valid().Can(obj.Cast< SQInteger >());
}
// Entry tag?
else if (obj.GetType() == OT_STRING)
{
Var< LightObj >::push(SqVM(), obj);
// Tag string
StackStrF tag(SqVM(), -1);
// Attempt extraction
if (SQ_FAILED(tag.Proc(false)))
{
// Restore the stack first
sq_poptop(SqVM());
// Now the exception
STHROWF("Unable to extract tag string");
}
// Restore the stack
sq_poptop(SqVM());
// Reference the instance
PvUnit & u = Valid();
// Generate and cache the hash
tag.CacheHash();
// Forward request
return u.Can(u.ValidManager().GetValidEntryWithTag(tag)->mID);
}
// Entry instance?
else if (obj.GetType() == OT_INSTANCE && obj.GetTypeTag() == StaticClassTypeTag< SqPvEntry >::Get())
{
return Valid().Can(obj.CastI< SqPvEntry >()->Valid().mID);
}
STHROWF("Unknown or unsupported entry identification type (%s)", SqTypeName(obj.GetType()));
SQ_UNREACHABLE
}
// ================================================================================================
void Register_Privilege_Unit(HSQUIRRELVM vm, Table & ns)
{
ns.Bind(_SC("Unit"),
Class< SqPvUnit, NoConstructor< SqPvUnit > >(vm, UnitTn::Str)
// Meta-methods
.SquirrelFunc(_SC("_typename"), &UnitTn::Fn)
.Func(_SC("_tostring"), &SqPvUnit::ToString)
// Core Properties
.Prop(_SC("ID"), &SqPvUnit::GetID)
.Prop(_SC("Tag"), &SqPvUnit::GetTag, &SqPvUnit::SetTag)
.Prop(_SC("Data"), &SqPvUnit::GetData, &SqPvUnit::SetData)
.Prop(_SC("Authority"), &SqPvUnit::GetAuthority, &SqPvUnit::SetAuthority)
.Prop(_SC("Manager"), &SqPvUnit::GetManager)
.Prop(_SC("Class"), &SqPvUnit::GetClass, &SqPvUnit::SetClass)
.Prop(_SC("Authority"), &SqPvUnit::GetAuthority, &SqPvUnit::SetAuthority)
// Core Methods
.FmtFunc(_SC("SetTag"), &SqPvUnit::ApplyTag)
.CbFunc(_SC("OnQuery"), &SqPvUnit::SetOnQuery)
.CbFunc(_SC("OnLost"), &SqPvUnit::SetOnLost)
.CbFunc(_SC("OnGained"), &SqPvUnit::SetOnGained)
// Member Methods
.Func(_SC("Can"), &SqPvUnit::Can)
);
}
} // Namespace:: SqMod

View File

@ -0,0 +1,281 @@
#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 AssignStatus(SQInteger id, SQInteger value);
/* --------------------------------------------------------------------------------------------
* Remove a status value. If the specified status value is not assigned, nothing happens.
*/
void RemoveStatus(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 ModifyStatus(SQInteger id, SQInteger value);
/* --------------------------------------------------------------------------------------------
* 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) 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) const;
};
} // Namespace:: SqMod