mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
First draft/prototype of built-in privilege management.
This commit is contained in:
parent
6d30202bbd
commit
90597e4287
@ -38,11 +38,17 @@ add_library(SqModule MODULE SqBase.hpp Main.cpp
|
|||||||
Core/Command.cpp Core/Command.hpp
|
Core/Command.cpp Core/Command.hpp
|
||||||
Core/Common.cpp Core/Common.hpp
|
Core/Common.cpp Core/Common.hpp
|
||||||
Core/Entity.cpp Core/Entity.hpp
|
Core/Entity.cpp Core/Entity.hpp
|
||||||
|
Core/Privilege.cpp Core/Privilege.hpp
|
||||||
|
Core/Privilege/Base.cpp Core/Privilege/Base.hpp
|
||||||
|
Core/Privilege/Class.cpp Core/Privilege/Class.hpp
|
||||||
|
Core/Privilege/Entry.cpp Core/Privilege/Entry.hpp
|
||||||
|
Core/Privilege/Unit.cpp Core/Privilege/Unit.hpp
|
||||||
Core/Routine.cpp Core/Routine.hpp
|
Core/Routine.cpp Core/Routine.hpp
|
||||||
Core/Script.cpp Core/Script.hpp
|
Core/Script.cpp Core/Script.hpp
|
||||||
Core/Signal.cpp Core/Signal.hpp
|
Core/Signal.cpp Core/Signal.hpp
|
||||||
Core/Tasks.cpp Core/Tasks.hpp
|
Core/Tasks.cpp Core/Tasks.hpp
|
||||||
Core/Utility.cpp Core/Utility.hpp
|
Core/Utility.cpp Core/Utility.hpp
|
||||||
|
Core/VecMap.hpp
|
||||||
# Entity
|
# Entity
|
||||||
Entity/Blip.cpp Entity/Blip.hpp
|
Entity/Blip.cpp Entity/Blip.hpp
|
||||||
Entity/Checkpoint.cpp Entity/Checkpoint.hpp
|
Entity/Checkpoint.cpp Entity/Checkpoint.hpp
|
||||||
|
@ -44,7 +44,7 @@ extern void InitializeTasks();
|
|||||||
extern void InitializeRoutines();
|
extern void InitializeRoutines();
|
||||||
extern void TerminateAreas();
|
extern void TerminateAreas();
|
||||||
extern void TerminateTasks();
|
extern void TerminateTasks();
|
||||||
//extern void TerminatePrivileges();
|
extern void TerminatePrivileges();
|
||||||
extern void TerminateRoutines();
|
extern void TerminateRoutines();
|
||||||
extern void TerminateCommands();
|
extern void TerminateCommands();
|
||||||
extern void TerminateSignals();
|
extern void TerminateSignals();
|
||||||
@ -501,7 +501,7 @@ void Core::Terminate(bool shutdown)
|
|||||||
// Release all managed areas
|
// Release all managed areas
|
||||||
TerminateAreas();
|
TerminateAreas();
|
||||||
// Release privilege managers
|
// Release privilege managers
|
||||||
//TerminatePrivileges();
|
TerminatePrivileges();
|
||||||
// Release announcers
|
// Release announcers
|
||||||
AnnounceTerminate();
|
AnnounceTerminate();
|
||||||
// Release ZMQ sockets
|
// Release ZMQ sockets
|
||||||
|
391
module/Core/Privilege.cpp
Normal file
391
module/Core/Privilege.cpp
Normal file
@ -0,0 +1,391 @@
|
|||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "Core/Privilege.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_DECL_TYPENAME(ManagerTn, _SC("SqPrivilegeManager"))
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void TerminatePrivileges()
|
||||||
|
{
|
||||||
|
// Go over all managers and try to close them
|
||||||
|
for (PvManager * inst = PvManager::sHead; inst && inst->mNext != PvManager::sHead; inst = inst->mNext)
|
||||||
|
{
|
||||||
|
inst->Terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void PvManager::Release()
|
||||||
|
{
|
||||||
|
// Release objects from this instance
|
||||||
|
m_OnQuery.Release();
|
||||||
|
m_OnGained.Release();
|
||||||
|
m_OnLost.Release();
|
||||||
|
m_Tag.Release();
|
||||||
|
m_Data.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void PvManager::Terminate()
|
||||||
|
{
|
||||||
|
// Release script objects held by classes
|
||||||
|
for (auto & c : m_Classes)
|
||||||
|
{
|
||||||
|
//c->Release();
|
||||||
|
}
|
||||||
|
// Release script objects held by units
|
||||||
|
for (auto & u : m_Units)
|
||||||
|
{
|
||||||
|
//c->Release();
|
||||||
|
}
|
||||||
|
// Release script objects held by entries
|
||||||
|
for (auto & e : m_Entries)
|
||||||
|
{
|
||||||
|
//c->Release();
|
||||||
|
}
|
||||||
|
// Release script objects held by the manager
|
||||||
|
Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
LightObj PvManager::CreateEntry(SQInteger id, StackStrF & name)
|
||||||
|
{
|
||||||
|
ModifyEntries();
|
||||||
|
// Look for a similar entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Is this unique?
|
||||||
|
if (itr != m_Entries.end())
|
||||||
|
{
|
||||||
|
STHROWF("Entry ({} : {}) already exists", id, name.mPtr);
|
||||||
|
}
|
||||||
|
// We backup the name hash now because I don't know if the move will happen before or after i create the identity
|
||||||
|
// Compiler optimizations and sh!t. (the name hash is cached in .mRes member variable)
|
||||||
|
const auto h = name.CacheHash().GetHash();
|
||||||
|
// Create it now
|
||||||
|
auto & e = m_Entries.emplace_back(PvIdentity(id, h), std::make_shared< PvEntry >(id, std::move(name), this));
|
||||||
|
// Create a wrapper instance and return it
|
||||||
|
return LightObj(SqTypeIdentity< SqPvEntry >{}, SqVM(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
LightObj PvManager::CreateClass(SQInteger id, StackStrF & name)
|
||||||
|
{
|
||||||
|
ModifyClasses();
|
||||||
|
// Look for a similar class
|
||||||
|
auto itr = m_Classes.find(PvIdentity(id));
|
||||||
|
// Is this unique?
|
||||||
|
if (itr != m_Classes.end())
|
||||||
|
{
|
||||||
|
STHROWF("Class ({} : {}) already exists", id, name.mPtr);
|
||||||
|
}
|
||||||
|
// We backup the name hash now because I don't know if the move will happen before or after i create the identity
|
||||||
|
// Compiler optimizations and sh!t. (the name hash is cached in .mRes member variable)
|
||||||
|
const auto h = name.CacheHash().GetHash();
|
||||||
|
// Create it now
|
||||||
|
auto & e = m_Classes.emplace_back(PvIdentity(id, h), std::make_shared< PvClass >(id, std::move(name), this));
|
||||||
|
// Create a wrapper instance and return it
|
||||||
|
return LightObj(SqTypeIdentity< SqPvClass >{}, SqVM(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
LightObj PvManager::CreateUnit(SQInteger id, const SqPvClass & cls, StackStrF & name)
|
||||||
|
{
|
||||||
|
ModifyUnits();
|
||||||
|
// Validate the given class
|
||||||
|
cls.Validate();
|
||||||
|
// Look for a similar unit
|
||||||
|
auto itr = m_Units.find(PvIdentity(id));
|
||||||
|
// Is this unique?
|
||||||
|
if (itr != m_Units.end())
|
||||||
|
{
|
||||||
|
STHROWF("Unit ({} : {}) already exists", id, name.mPtr);
|
||||||
|
}
|
||||||
|
// We backup the name hash now because I don't know if the move will happen before or after i create the identity
|
||||||
|
// Compiler optimizations and sh!t. (the name hash is cached in .mRes member variable)
|
||||||
|
const auto h = name.CacheHash().GetHash();
|
||||||
|
// Create it now
|
||||||
|
auto & e = m_Units.emplace_back(PvIdentity(id, h), std::make_shared< PvUnit >(id, std::move(name), cls.mI));
|
||||||
|
// Create a wrapper instance and return it
|
||||||
|
return LightObj(SqTypeIdentity< SqPvUnit >{}, SqVM(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void PvManager::PropagateParentAssign(const PvClass & cls, const PvClass::Ref & parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void PvManager::PropagateParentChange(const PvClass & cls, const PvClass::Ref & parent)
|
||||||
|
{
|
||||||
|
// Prevent any changes to entries during this operation
|
||||||
|
AutoAssign< bool > aag(m_LockEntries, false, true);
|
||||||
|
// Go over all entries and see if the specified class will gain or loose any privileges from this change
|
||||||
|
for (const auto & e : m_Entries)
|
||||||
|
{
|
||||||
|
// Owned privileges are not affected regardless of the inherited class
|
||||||
|
{
|
||||||
|
// See if this class inherits the current entry
|
||||||
|
auto itr = cls.mPrivileges.find(e.second->mID);
|
||||||
|
// Is this entry inherited or owned?
|
||||||
|
if (itr != cls.mPrivileges.end())
|
||||||
|
{
|
||||||
|
break; // Nothing new will happen here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We know we inherit this entry value so let's get that value instead
|
||||||
|
SQInteger inherited = cls.GetInheritedEntryValue(e.second->mID);
|
||||||
|
// Get the value that will be inherited for this entry
|
||||||
|
SQInteger current = parent->GetEntryValue(e.second->mID);
|
||||||
|
// Are they literally the same?
|
||||||
|
if (inherited == current)
|
||||||
|
{
|
||||||
|
break; // Don't even bother
|
||||||
|
}
|
||||||
|
// Find out who can identify this change
|
||||||
|
const Function & modify = e.second->mOnModify.IsNull() ? m_OnModify : e.second->mOnModify;
|
||||||
|
// Is there someone that can identify this change?
|
||||||
|
if (!modify.IsNull())
|
||||||
|
{
|
||||||
|
LightObj r = modify.Eval(inherited, current);
|
||||||
|
// Was this considered a change?
|
||||||
|
if (!r.IsNull())
|
||||||
|
{
|
||||||
|
cls.DoChanged(e.second->mID, r.Cast< bool >(), current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// By default we use > comparison to decide upgrades
|
||||||
|
cls.DoChanged(e.second->mID, current > inherited, current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
void PvManager::PropagateClassChange(const PvUnit & unit, const PvClass::Ref & cls)
|
||||||
|
{
|
||||||
|
// Prevent any changes to entries during this operation
|
||||||
|
AutoAssign< bool > aag(m_LockEntries, false, true);
|
||||||
|
// Go over all entries and see if the specified unit will gain or loose any privileges from this change
|
||||||
|
for (const auto & e : m_Entries)
|
||||||
|
{
|
||||||
|
// Owned privileges are not affected regardless of the inherited class
|
||||||
|
{
|
||||||
|
// See if this unit inherits the current entry
|
||||||
|
auto itr = unit.mPrivileges.find(e.second->mID);
|
||||||
|
// Is this entry inherited or owned?
|
||||||
|
if (itr != unit.mPrivileges.end())
|
||||||
|
{
|
||||||
|
break; // Nothing new will happen here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// We know we inherit this entry value so let's get that value instead
|
||||||
|
SQInteger inherited = unit.GetInheritedEntryValue(e.second->mID);
|
||||||
|
// Get the value that will be inherited for this entry
|
||||||
|
SQInteger current = cls->GetEntryValue(e.second->mID);
|
||||||
|
// Are they literally the same?
|
||||||
|
if (inherited == current)
|
||||||
|
{
|
||||||
|
break; // Don't even bother
|
||||||
|
}
|
||||||
|
// Find out who can identify this change
|
||||||
|
const Function & modify = e.second->mOnModify.IsNull() ? m_OnModify : e.second->mOnModify;
|
||||||
|
// Is there someone that can identify this change?
|
||||||
|
if (!modify.IsNull())
|
||||||
|
{
|
||||||
|
LightObj r = modify.Eval(inherited, current);
|
||||||
|
// Was this considered a change?
|
||||||
|
if (!r.IsNull())
|
||||||
|
{
|
||||||
|
unit.DoChanged(e.second->mID, r.Cast< bool >(), current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// By default we use > comparison to decide upgrades
|
||||||
|
unit.DoChanged(e.second->mID, current > inherited, current);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_NODISCARD LightObj PvManager::GetEntryWithID(SQInteger id)
|
||||||
|
{
|
||||||
|
return LightObj(SqTypeIdentity< SqPvEntry >{}, SqVM(), GetValidEntry(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_NODISCARD LightObj PvManager::GetEntryWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
return LightObj(SqTypeIdentity< SqPvEntry >{}, SqVM(), GetValidEntryWithTag(tag.CacheHash()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool PvManager::HaveEntryWithID(SQInteger id)
|
||||||
|
{
|
||||||
|
for (const auto & e : m_Entries) // NOLINT(readability-use-anyofallof)
|
||||||
|
{
|
||||||
|
if (e.first.mID == id)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool PvManager::HaveEntryWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
const size_t h = tag.ToHash();
|
||||||
|
for (const auto & e : m_Entries) // NOLINT(readability-use-anyofallof)
|
||||||
|
{
|
||||||
|
if (e.first.mHash == h)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_NODISCARD LightObj PvManager::GetClassWithID(SQInteger id)
|
||||||
|
{
|
||||||
|
return LightObj(SqTypeIdentity< SqPvClass >{}, SqVM(), GetValidClass(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_NODISCARD LightObj PvManager::GetClassWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
return LightObj(SqTypeIdentity< SqPvClass >{}, SqVM(), GetValidClassWithTag(tag.CacheHash()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool PvManager::HaveClassWithID(SQInteger id)
|
||||||
|
{
|
||||||
|
for (const auto & c : m_Classes) // NOLINT(readability-use-anyofallof)
|
||||||
|
{
|
||||||
|
if (c.first.mID == id)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool PvManager::HaveClassWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
const size_t h = tag.ToHash();
|
||||||
|
for (const auto & c : m_Classes) // NOLINT(readability-use-anyofallof)
|
||||||
|
{
|
||||||
|
if (c.first.mHash == h)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_NODISCARD LightObj PvManager::GetUnitWithID(SQInteger id)
|
||||||
|
{
|
||||||
|
return LightObj(SqTypeIdentity< SqPvUnit >{}, SqVM(), GetValidUnit(id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
SQMOD_NODISCARD LightObj PvManager::GetUnitWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
return LightObj(SqTypeIdentity< SqPvUnit >{}, SqVM(), GetValidUnitWithTag(tag.CacheHash()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool PvManager::HaveUnitWithID(SQInteger id)
|
||||||
|
{
|
||||||
|
for (const auto & u : m_Units) // NOLINT(readability-use-anyofallof)
|
||||||
|
{
|
||||||
|
if (u.first.mID == id)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
bool PvManager::HaveUnitWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
const size_t h = tag.ToHash();
|
||||||
|
for (const auto & u : m_Units) // NOLINT(readability-use-anyofallof)
|
||||||
|
{
|
||||||
|
if (u.first.mHash == h)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
extern void Register_Privilege_Class(HSQUIRRELVM vm, Table & ns);
|
||||||
|
extern void Register_Privilege_Entry(HSQUIRRELVM vm, Table & ns);
|
||||||
|
extern void Register_Privilege_Unit(HSQUIRRELVM vm, Table & ns);
|
||||||
|
|
||||||
|
// ================================================================================================
|
||||||
|
void Register_Privilege(HSQUIRRELVM vm)
|
||||||
|
{
|
||||||
|
Table ns(vm);
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
Register_Privilege_Class(vm, ns);
|
||||||
|
Register_Privilege_Entry(vm, ns);
|
||||||
|
Register_Privilege_Unit(vm, ns);
|
||||||
|
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
ns.Bind(_SC("Manager"),
|
||||||
|
Class< PvManager, NoCopy< PvManager > >(vm, ManagerTn::Str)
|
||||||
|
// Constructors
|
||||||
|
.Ctor()
|
||||||
|
.Ctor< StackStrF & >()
|
||||||
|
// Meta-methods
|
||||||
|
.SquirrelFunc(_SC("_typename"), &ManagerTn::Fn)
|
||||||
|
.Func(_SC("_tostring"), &PvManager::ToString)
|
||||||
|
// Core Properties
|
||||||
|
.Prop(_SC("Tag"), &PvManager::GetTag, &PvManager::SetTag)
|
||||||
|
.Prop(_SC("Data"), &PvManager::GetData, &PvManager::SetData)
|
||||||
|
// Core Methods
|
||||||
|
.FmtFunc(_SC("SetTag"), &PvManager::ApplyTag)
|
||||||
|
.CbFunc(_SC("OnQuery"), &PvManager::SetOnQuery)
|
||||||
|
.CbFunc(_SC("OnLost"), &PvManager::SetOnLost)
|
||||||
|
.CbFunc(_SC("OnGained"), &PvManager::SetOnGained)
|
||||||
|
// Member Methods
|
||||||
|
.CbFunc(_SC("CreateEntry"), &PvManager::CreateEntry)
|
||||||
|
.CbFunc(_SC("CreateClass"), &PvManager::CreateClass)
|
||||||
|
.CbFunc(_SC("CreateUnit"), &PvManager::CreateUnit)
|
||||||
|
.Func(_SC("GetEntry"), &PvManager::GetEntryWithID)
|
||||||
|
.FmtFunc(_SC("GetEntryWithTag"), &PvManager::GetEntryWithTag)
|
||||||
|
.Func(_SC("HaveEntry"), &PvManager::HaveEntryWithID)
|
||||||
|
.FmtFunc(_SC("HaveEntryWithTag"), &PvManager::HaveEntryWithTag)
|
||||||
|
.Func(_SC("GetClass"), &PvManager::GetClassWithID)
|
||||||
|
.FmtFunc(_SC("GetClassWithTag"), &PvManager::GetClassWithTag)
|
||||||
|
.Func(_SC("HaveClass"), &PvManager::HaveClassWithID)
|
||||||
|
.FmtFunc(_SC("HaveClassWithTag"), &PvManager::HaveClassWithTag)
|
||||||
|
.Func(_SC("GetUnit"), &PvManager::GetUnitWithID)
|
||||||
|
.FmtFunc(_SC("GetUnitWithTag"), &PvManager::GetUnitWithTag)
|
||||||
|
.Func(_SC("HaveUnit"), &PvManager::HaveUnitWithID)
|
||||||
|
.FmtFunc(_SC("HaveUnitWithTag"), &PvManager::HaveUnitWithTag)
|
||||||
|
);
|
||||||
|
|
||||||
|
RootTable(vm).Bind(_SC("SqPrivilege"), ns);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Namespace:: SqMod
|
621
module/Core/Privilege.hpp
Normal file
621
module/Core/Privilege.hpp
Normal file
@ -0,0 +1,621 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* This could have been much more flexible and advanced than this (as initially planned).
|
||||||
|
* However, several factors played an important role in its current simplicity:
|
||||||
|
* 1) Time constraints:
|
||||||
|
* This had to be done over the course of a weekend (at worst). It might be extended
|
||||||
|
* over time but right now this will do.
|
||||||
|
* 2) Performance cost:
|
||||||
|
* Privilege micro-management will become costly if scripting is involved. Therefore, several
|
||||||
|
* sacrifices had to be made. Such as type-agnostic status value, script controlled query etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "Core/Privilege/Class.hpp"
|
||||||
|
#include "Core/Privilege/Entry.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
namespace SqMod {
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* Privilege manager responsible for keeping track of each resource and handling requests.
|
||||||
|
*/
|
||||||
|
struct PvManager : SqChainedInstances< PvManager >
|
||||||
|
{
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Container that stores privilege entries.
|
||||||
|
*/
|
||||||
|
PvEntry::List m_Entries;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Container that stores the managed classes.
|
||||||
|
*/
|
||||||
|
PvClass::List m_Classes;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Container that stores all the managed units.
|
||||||
|
*/
|
||||||
|
PvUnit::List m_Units;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Dedicated callback for privilege query event.
|
||||||
|
*/
|
||||||
|
Function m_OnQuery;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Dedicated callback for privilege modify event.
|
||||||
|
*/
|
||||||
|
Function m_OnModify;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Dedicated callback for privilege gained event.
|
||||||
|
*/
|
||||||
|
Function m_OnGained;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Dedicated callback for privilege lost event.
|
||||||
|
*/
|
||||||
|
Function m_OnLost;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* User tag associated with this instance.
|
||||||
|
*/
|
||||||
|
StackStrF m_Tag;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* User data associated with this instance.
|
||||||
|
*/
|
||||||
|
LightObj m_Data;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Used to prevent modification of entries, classes or units.
|
||||||
|
*/
|
||||||
|
bool m_LockEntries;
|
||||||
|
bool m_LockClasses;
|
||||||
|
bool m_LockUnits;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
PvManager()
|
||||||
|
: m_Entries(), m_Classes(), m_Units()
|
||||||
|
, m_OnQuery(), m_OnModify(), m_OnGained(), m_OnLost()
|
||||||
|
, m_Tag(), m_Data()
|
||||||
|
, m_LockEntries(false), m_LockClasses(false), m_LockUnits(false)
|
||||||
|
{
|
||||||
|
// Remember this instance
|
||||||
|
ChainInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
explicit PvManager(StackStrF & tag)
|
||||||
|
: m_Entries(), m_Classes(), m_Units()
|
||||||
|
, m_OnQuery(), m_OnModify(), m_OnGained(), m_OnLost()
|
||||||
|
, m_Tag(std::move(tag)), m_Data()
|
||||||
|
, m_LockEntries(false), m_LockClasses(false), m_LockUnits(false)
|
||||||
|
{
|
||||||
|
// Remember this instance
|
||||||
|
ChainInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Copy constructor (disabled).
|
||||||
|
*/
|
||||||
|
PvManager(const PvManager & o) = delete;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Move constructor (disabled).
|
||||||
|
*/
|
||||||
|
PvManager(PvManager && o) = delete;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~PvManager()
|
||||||
|
{
|
||||||
|
// Forget about this instance
|
||||||
|
UnchainInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Copy assignment operator (disabled).
|
||||||
|
*/
|
||||||
|
PvManager & operator = (const PvManager & o) = delete;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------------------------
|
||||||
|
* Move assignment operator (disabled).
|
||||||
|
*/
|
||||||
|
PvManager & operator = (PvManager && o) = delete;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Used by the script engine to convert an instance of this type to a string.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD auto ToString() const
|
||||||
|
{
|
||||||
|
return m_Tag.mObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the associated user tag.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD auto GetTag() const
|
||||||
|
{
|
||||||
|
return m_Tag.mObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Modify the associated user tag.
|
||||||
|
*/
|
||||||
|
void SetTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
m_Tag = std::move(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Modify the associated user tag.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD PvManager & ApplyTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
SetTag(tag);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the associated user data.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD LightObj & GetData()
|
||||||
|
{
|
||||||
|
return m_Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Modify the associated user data.
|
||||||
|
*/
|
||||||
|
void SetData(LightObj & data)
|
||||||
|
{
|
||||||
|
m_Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Release all script resources. Recursively forward request to all classes, units and entries.
|
||||||
|
*/
|
||||||
|
void Release();
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Terminate the all managers by releasing their classes and units and callbacks.
|
||||||
|
*/
|
||||||
|
void Terminate();
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Makes sure you can modify current entries.
|
||||||
|
*/
|
||||||
|
void ModifyEntries()
|
||||||
|
{
|
||||||
|
if (m_LockEntries)
|
||||||
|
{
|
||||||
|
STHROWF("Entries cannot be modified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Makes sure you can modify current entries.
|
||||||
|
*/
|
||||||
|
void ModifyClasses()
|
||||||
|
{
|
||||||
|
if (m_LockClasses)
|
||||||
|
{
|
||||||
|
STHROWF("Classes cannot be modified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Makes sure you can modify current entries.
|
||||||
|
*/
|
||||||
|
void ModifyUnits()
|
||||||
|
{
|
||||||
|
if (m_LockUnits)
|
||||||
|
{
|
||||||
|
STHROWF("Units cannot be modified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Bind a script function to the status query callback.
|
||||||
|
*/
|
||||||
|
void SetOnQuery(Function & func)
|
||||||
|
{
|
||||||
|
m_OnQuery = std::move(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the function bound to the status query callback.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const Function & GetOnQuery() const
|
||||||
|
{
|
||||||
|
return m_OnQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Find out the callback that must be invoked to handle query events for a certain entry.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const Function & GetOnQuery(SQInteger id) const
|
||||||
|
{
|
||||||
|
// Look for a the specified entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Does the specified entry exist?
|
||||||
|
if (itr != m_Entries.end())
|
||||||
|
{
|
||||||
|
return itr->second->mOnQuery;
|
||||||
|
}
|
||||||
|
// Default to the global one
|
||||||
|
return m_OnQuery;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Bind a script function to the status modify callback.
|
||||||
|
*/
|
||||||
|
void SetOnModify(Function & func)
|
||||||
|
{
|
||||||
|
m_OnModify = std::move(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the function bound to the status modify callback.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const Function & GetOnModify() const
|
||||||
|
{
|
||||||
|
return m_OnModify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Find out the callback that must be invoked to handle modify events for a certain entry.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const Function & GetOnModify(SQInteger id) const
|
||||||
|
{
|
||||||
|
// Look for a the specified entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Does the specified entry exist?
|
||||||
|
if (itr != m_Entries.end())
|
||||||
|
{
|
||||||
|
return itr->second->mOnModify;
|
||||||
|
}
|
||||||
|
// Default to the global one
|
||||||
|
return m_OnModify;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Bind a script function to the status gained callback.
|
||||||
|
*/
|
||||||
|
void SetOnGained(Function & func)
|
||||||
|
{
|
||||||
|
m_OnGained = std::move(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the function bound to the status gained callback.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const Function & GetOnGained() const
|
||||||
|
{
|
||||||
|
return m_OnGained;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Find out the callback that must be invoked to handle gained events for a certain entry.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const Function & GetOnGained(SQInteger id) const
|
||||||
|
{
|
||||||
|
// Look for a the specified entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Does the specified entry exist?
|
||||||
|
if (itr != m_Entries.end())
|
||||||
|
{
|
||||||
|
return itr->second->mOnGained;
|
||||||
|
}
|
||||||
|
// Default to the global one
|
||||||
|
return m_OnGained;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Bind a script function to the status lost callback.
|
||||||
|
*/
|
||||||
|
void SetOnLost(Function & func)
|
||||||
|
{
|
||||||
|
m_OnLost = std::move(func);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the function bound to the status lost callback.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD Function & GetOnLost()
|
||||||
|
{
|
||||||
|
return m_OnLost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Find out the callback that must be invoked to handle lost events for a certain entry.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD Function & GetOnLost(SQInteger id)
|
||||||
|
{
|
||||||
|
// Look for a the specified entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Does the specified entry exist?
|
||||||
|
if (itr != m_Entries.end())
|
||||||
|
{
|
||||||
|
return itr->second->mOnLost;
|
||||||
|
}
|
||||||
|
// Default to the global one
|
||||||
|
return m_OnLost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific entry exists and return a smart reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const PvEntry::Ref & GetValidEntry(SQInteger id)
|
||||||
|
{
|
||||||
|
// Look for a the specified entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Does this entry exist?
|
||||||
|
if (itr == m_Entries.end())
|
||||||
|
{
|
||||||
|
STHROWF("Entry ({}) doesn't exists", id);
|
||||||
|
}
|
||||||
|
// Return the reference
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific class exists and return a smart reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const PvClass::Ref & GetValidClass(SQInteger id)
|
||||||
|
{
|
||||||
|
// Look for a the specified class
|
||||||
|
auto itr = m_Classes.find(PvIdentity(id));
|
||||||
|
// Does this class exist?
|
||||||
|
if (itr == m_Classes.end())
|
||||||
|
{
|
||||||
|
STHROWF("Class ({}) doesn't exists", id);
|
||||||
|
}
|
||||||
|
// Return the reference
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific unit exists and return a smart reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const PvUnit::Ref & GetValidUnit(SQInteger id)
|
||||||
|
{
|
||||||
|
// Look for a the specified unit
|
||||||
|
auto itr = m_Units.find(PvIdentity(id));
|
||||||
|
// Does this unit exist?
|
||||||
|
if (itr == m_Units.end())
|
||||||
|
{
|
||||||
|
STHROWF("Unit ({}) doesn't exists", id);
|
||||||
|
}
|
||||||
|
// Return the reference
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific entry exists and return a reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD PvEntry & ValidEntry(SQInteger id) { return *GetValidEntry(id); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific class exists and return a reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD PvClass & ValidClass(SQInteger id) { return *GetValidClass(id); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific unit exists and return a reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD PvUnit & ValidUnit(SQInteger id) { return *GetValidUnit(id); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific entry exists and return a smart reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const PvEntry::Ref & GetValidEntryWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
const size_t h = tag.GetHash();
|
||||||
|
for (const auto & e : m_Entries)
|
||||||
|
{
|
||||||
|
if (e.first.mHash == h)
|
||||||
|
{
|
||||||
|
return e.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
STHROWF("Entry ({}) doesn't exists", tag.mPtr);
|
||||||
|
SQ_UNREACHABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific class exists and return a smart reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const PvClass::Ref & GetValidClassWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
const size_t h = tag.GetHash();
|
||||||
|
for (const auto & c : m_Classes)
|
||||||
|
{
|
||||||
|
if (c.first.mHash == h)
|
||||||
|
{
|
||||||
|
return c.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
STHROWF("Class ({}) doesn't exists", tag.mPtr);
|
||||||
|
SQ_UNREACHABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Make sure a specific unit exists and return a smart reference to it.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD const PvUnit::Ref & GetValidUnitWithTag(StackStrF & tag)
|
||||||
|
{
|
||||||
|
const size_t h = tag.GetHash();
|
||||||
|
for (const auto & u : m_Units)
|
||||||
|
{
|
||||||
|
if (u.first.mHash == h)
|
||||||
|
{
|
||||||
|
return u.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Not found
|
||||||
|
STHROWF("Unit ({}) doesn't exists", tag.mPtr);
|
||||||
|
SQ_UNREACHABLE
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the default value of an entry.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD SQInteger GetEntryValue(SQInteger id) const
|
||||||
|
{
|
||||||
|
// Look for a the specified entry
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Does this entry exist?
|
||||||
|
if (itr == m_Entries.end())
|
||||||
|
{
|
||||||
|
STHROWF("Entry ({}) doesn't exists", id);
|
||||||
|
}
|
||||||
|
// Return the associated callback
|
||||||
|
return itr->second->mDefault;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Update the hash of the specified entry.
|
||||||
|
*/
|
||||||
|
void UpdateEntryHash(SQInteger id, size_t hash)
|
||||||
|
{
|
||||||
|
auto itr = m_Entries.find(PvIdentity(id));
|
||||||
|
// Only update if it exists
|
||||||
|
if (itr != m_Entries.end())
|
||||||
|
{
|
||||||
|
itr->first.mHash = hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Update the hash of the specified class.
|
||||||
|
*/
|
||||||
|
void UpdateClassHash(SQInteger id, size_t hash)
|
||||||
|
{
|
||||||
|
auto itr = m_Classes.find(PvIdentity(id));
|
||||||
|
// Only update if it exists
|
||||||
|
if (itr != m_Classes.end())
|
||||||
|
{
|
||||||
|
itr->first.mHash = hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Update the hash of the specified unit.
|
||||||
|
*/
|
||||||
|
void UpdateUnitHash(SQInteger id, size_t hash)
|
||||||
|
{
|
||||||
|
auto itr = m_Units.find(PvIdentity(id));
|
||||||
|
// Only update if it exists
|
||||||
|
if (itr != m_Units.end())
|
||||||
|
{
|
||||||
|
itr->first.mHash = hash;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Create a entry unit. It throws an error if it already exists.
|
||||||
|
*/
|
||||||
|
LightObj CreateEntry(SQInteger id, StackStrF & name);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Create a class unit. It throws an error if it already exists.
|
||||||
|
*/
|
||||||
|
LightObj CreateClass(SQInteger id, StackStrF & name);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Create a unit unit. It throws an error if it already exists.
|
||||||
|
*/
|
||||||
|
LightObj CreateUnit(SQInteger id, const SqPvClass & cls, StackStrF & name);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Performs the necessary checks to see if privileges were gained or lost when changing classes.
|
||||||
|
*/
|
||||||
|
void PropagateParentAssign(const PvClass & cls, const PvClass::Ref & parent);
|
||||||
|
void PropagateParentAssign(const PvClass::Ref & cls, const PvClass::Ref & parent) { PropagateParentAssign(*cls, parent); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Performs the necessary checks to see if privileges were gained or lost when changing classes.
|
||||||
|
*/
|
||||||
|
void PropagateParentChange(const PvClass & cls, const PvClass::Ref & parent);
|
||||||
|
void PropagateParentChange(const PvClass::Ref & cls, const PvClass::Ref & parent) { PropagateParentChange(*cls, parent); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Performs the necessary checks to see if privileges were gained or lost when changing classes.
|
||||||
|
*/
|
||||||
|
void PropagateClassChange(const PvUnit & unit, const PvClass::Ref & cls);
|
||||||
|
void PropagateClassChange(const PvUnit::Ref & unit, const PvClass::Ref & cls) { PropagateClassChange(*unit, cls); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a entry with a certain identifier inherits this class.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD LightObj GetEntryWithID(SQInteger id);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a entry with a certain tag inherits this class.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD LightObj GetEntryWithTag(StackStrF & tag);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a entry with a certain identifier inherits this class.
|
||||||
|
*/
|
||||||
|
bool HaveEntryWithID(SQInteger id);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a entry with a certain tag inherits this class.
|
||||||
|
*/
|
||||||
|
bool HaveEntryWithTag(StackStrF & tag);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a class with a certain identifier inherits this class.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD LightObj GetClassWithID(SQInteger id);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a class with a certain tag inherits this class.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD LightObj GetClassWithTag(StackStrF & tag);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a class with a certain identifier inherits this class.
|
||||||
|
*/
|
||||||
|
bool HaveClassWithID(SQInteger id);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* See if a class with a certain tag inherits this class.
|
||||||
|
*/
|
||||||
|
bool HaveClassWithTag(StackStrF & tag);
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* 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);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // Namespace:: SqMod
|
9
module/Core/Privilege/Base.cpp
Normal file
9
module/Core/Privilege/Base.cpp
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "Core/Privilege/Base.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
namespace SqMod {
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
} // Namespace:: SqMod
|
105
module/Core/Privilege/Base.hpp
Normal file
105
module/Core/Privilege/Base.hpp
Normal 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
|
404
module/Core/Privilege/Class.cpp
Normal file
404
module/Core/Privilege/Class.cpp
Normal 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
|
335
module/Core/Privilege/Class.hpp
Normal file
335
module/Core/Privilege/Class.hpp
Normal 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
|
66
module/Core/Privilege/Entry.cpp
Normal file
66
module/Core/Privilege/Entry.cpp
Normal 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
|
188
module/Core/Privilege/Entry.hpp
Normal file
188
module/Core/Privilege/Entry.hpp
Normal 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
|
370
module/Core/Privilege/Unit.cpp
Normal file
370
module/Core/Privilege/Unit.cpp
Normal 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
|
281
module/Core/Privilege/Unit.hpp
Normal file
281
module/Core/Privilege/Unit.hpp
Normal 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
|
258
module/Core/VecMap.hpp
Normal file
258
module/Core/VecMap.hpp
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include "SqBase.hpp"
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------------------------
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <functional>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* Hybrid associative container combining the performance of a vector and usefulness of a map container.
|
||||||
|
* This class works under the assumption that you are not stupid enough to modify the keys yourself.
|
||||||
|
* It does not try to replace std::map but rather provide a few helper methods to avoid duplicate code.
|
||||||
|
*/
|
||||||
|
template < class Key, class T, class Pred = std::equal_to< Key > > struct VecMap
|
||||||
|
{
|
||||||
|
// --------------------------------------------------------------------------------------------
|
||||||
|
using key_type = Key;
|
||||||
|
using mapped_type = T;
|
||||||
|
using value_type = std::pair< Key, T >;
|
||||||
|
using storage_type = std::vector< value_type >;
|
||||||
|
using key_equal = Pred;
|
||||||
|
using pointer = typename storage_type::pointer;
|
||||||
|
using const_pointer = typename storage_type::const_pointer;
|
||||||
|
using reference = typename storage_type::reference;
|
||||||
|
using const_reference = typename storage_type::const_reference;
|
||||||
|
using size_type = typename storage_type::size_type;
|
||||||
|
using difference_type = typename storage_type::difference_type;
|
||||||
|
using iterator = typename storage_type::iterator;
|
||||||
|
using const_iterator = typename storage_type::const_iterator;
|
||||||
|
using insert_return_type = std::pair< iterator, pointer >;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
VecMap() noexcept(noexcept(storage_type())) = default;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copy constructor. Does exactly what you expect it to do.
|
||||||
|
*/
|
||||||
|
VecMap(const VecMap & o) = default;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Move constructor. Does exactly what you expect it to do.
|
||||||
|
*/
|
||||||
|
VecMap(VecMap && o) noexcept = default;
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Sub-script operator.
|
||||||
|
*/
|
||||||
|
mapped_type & operator [] (const key_type & key)
|
||||||
|
{
|
||||||
|
Pred p;
|
||||||
|
for (auto & e : m_Storage)
|
||||||
|
{
|
||||||
|
if (p(e.first, key)) return e.second;
|
||||||
|
}
|
||||||
|
m_Storage.emplace_back(key, mapped_type{});
|
||||||
|
return m_Storage.back().second;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve an iterator to the beginning. See: std::vector::begin()
|
||||||
|
*/
|
||||||
|
iterator begin() noexcept { return m_Storage.begin(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve an iterator to the beginning (const). See: std::vector::[c]begin()
|
||||||
|
*/
|
||||||
|
const_iterator begin() const noexcept { return m_Storage.begin(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve an iterator to the beginning (const). See: std::vector::cbegin()
|
||||||
|
*/
|
||||||
|
const_iterator cbegin() const noexcept { return m_Storage.cbegin(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve an iterator to the beginning. See: std::vector::end()
|
||||||
|
*/
|
||||||
|
iterator end() noexcept { return m_Storage.end(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve an iterator to the beginning (const). See: std::vector::[c]end()
|
||||||
|
*/
|
||||||
|
const_iterator end() const noexcept { return m_Storage.end(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve an iterator to the beginning (const). See: std::vector::cend()
|
||||||
|
*/
|
||||||
|
const_iterator cend() const noexcept { return m_Storage.cend(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a reverse iterator to the beginning. See: std::vector::rbegin()
|
||||||
|
*/
|
||||||
|
iterator rbegin() noexcept { return m_Storage.rbegin(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a reverse iterator to the beginning (const). See: std::vector::[c]rbegin()
|
||||||
|
*/
|
||||||
|
const_iterator rbegin() const noexcept { return m_Storage.rbegin(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a reverse iterator to the beginning (const). See: std::vector::crbegin()
|
||||||
|
*/
|
||||||
|
const_iterator crbegin() const noexcept { return m_Storage.crbegin(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a reverse iterator to the beginning. See: std::vector::rend()
|
||||||
|
*/
|
||||||
|
iterator rend() noexcept { return m_Storage.rend(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a reverse iterator to the beginning (const). See: std::vector::[c]rend()
|
||||||
|
*/
|
||||||
|
const_iterator rend() const noexcept { return m_Storage.rend(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve a reverse iterator to the beginning (const). See: std::vector::crend()
|
||||||
|
*/
|
||||||
|
const_iterator crend() const noexcept { return m_Storage.crend(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Check if elements are stored in the container.
|
||||||
|
*/
|
||||||
|
SQMOD_NODISCARD bool empty() const noexcept { return m_Storage.empty(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the number of elements stored in the container.
|
||||||
|
*/
|
||||||
|
size_type size() const noexcept { return m_Storage.size(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the number of elements that can be stored in the container.
|
||||||
|
*/
|
||||||
|
size_type max_size() const noexcept { return m_Storage.max_size(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Reserve space for a specific amount of elements.
|
||||||
|
*/
|
||||||
|
void reserve(size_type n) { m_Storage.reserve(n); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Retrieve the number of elements that can be held in currently allocated storage.
|
||||||
|
*/
|
||||||
|
size_type capacity() const noexcept { return m_Storage.capacity(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Reduce memory usage by freeing unused memory.
|
||||||
|
*/
|
||||||
|
void conform() { m_Storage.shrink_to_fit(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Discard all stored elements.
|
||||||
|
*/
|
||||||
|
void clear() noexcept { m_Storage.clear(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Locate a an element with a specific key and obtain an iterator to it's location.
|
||||||
|
*/
|
||||||
|
iterator find(const key_type & key) noexcept
|
||||||
|
{
|
||||||
|
return std::find_if(m_Storage.begin(), m_Storage.end(),
|
||||||
|
[&, p = Pred()](reference e) -> bool { return p(e.first, key); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Locate a an element with a specific key and obtain an iterator to it's location.
|
||||||
|
*/
|
||||||
|
const_iterator find(const key_type & key) const noexcept
|
||||||
|
{
|
||||||
|
return std::find_if(m_Storage.cbegin(), m_Storage.cend(),
|
||||||
|
[&, p = Pred()](const_reference e) -> bool { return p(e.first, key); });
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Check if an element with a specific key exists in the container.
|
||||||
|
*/
|
||||||
|
bool exists(const key_type & key) const noexcept { return find(key) != m_Storage.cend(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Append a new element to the end of the container.
|
||||||
|
*/
|
||||||
|
template< class... Args > mapped_type & try_emplace(const key_type & k, Args&&... args)
|
||||||
|
{
|
||||||
|
auto itr = find(k);
|
||||||
|
if (itr != m_Storage.end())
|
||||||
|
{
|
||||||
|
itr->second = mapped_type(std::forward< Args >(args)...);
|
||||||
|
return *itr;
|
||||||
|
}
|
||||||
|
m_Storage.emplace_back(k, std::forward< Args >(args)...);
|
||||||
|
return m_Storage.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Append a new element to the end of the container.
|
||||||
|
*/
|
||||||
|
template< class... Args > mapped_type & try_emplace(key_type && k, Args&&... args)
|
||||||
|
{
|
||||||
|
auto itr = find(k);
|
||||||
|
if (itr != m_Storage.end())
|
||||||
|
{
|
||||||
|
itr->second = mapped_type(std::forward< Args >(args)...);
|
||||||
|
return *itr;
|
||||||
|
}
|
||||||
|
m_Storage.emplace_back(std::move(k), std::forward< Args >(args)...);
|
||||||
|
return m_Storage.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Remove the last element of the container.
|
||||||
|
*/
|
||||||
|
void pop_back() { m_Storage.pop_back(); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Removes specified element from the container. Returns true if found and removed, false otherwise.
|
||||||
|
*/
|
||||||
|
bool erase(const key_type & key)
|
||||||
|
{
|
||||||
|
auto itr = find(key);
|
||||||
|
if (itr != m_Storage.end())
|
||||||
|
{
|
||||||
|
m_Storage.erase(itr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Removes specified element from the container. Returns iterator to the next element.
|
||||||
|
*/
|
||||||
|
iterator erase(iterator pos) { return m_Storage.erase(pos); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Removes specified element from the container. Returns iterator to the next element.
|
||||||
|
*/
|
||||||
|
iterator erase(const_iterator pos) { return m_Storage.erase(pos); }
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Append a new element to the end of the container.
|
||||||
|
* Available for internal use when the search was already performed.
|
||||||
|
*/
|
||||||
|
template< class... Args > mapped_type & emplace_back( Args&&... args )
|
||||||
|
{
|
||||||
|
m_Storage.emplace_back(std::forward< Args >(args)...);
|
||||||
|
return m_Storage.back().second;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Internal container used to store elements.
|
||||||
|
*/
|
||||||
|
storage_type m_Storage;
|
||||||
|
};
|
@ -94,7 +94,7 @@ bool RegisterAPI(HSQUIRRELVM vm)
|
|||||||
Register_Log(vm);
|
Register_Log(vm);
|
||||||
Register_Core(vm);
|
Register_Core(vm);
|
||||||
Register_Command(vm);
|
Register_Command(vm);
|
||||||
//Register_Privilege(vm);
|
Register_Privilege(vm);
|
||||||
Register_Routine(vm);
|
Register_Routine(vm);
|
||||||
Register_Tasks(vm);
|
Register_Tasks(vm);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user