1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00
SqMod/module/Core/Privilege.cpp
Sandu Liviu Catalin 479272d59f Add iteration.
2021-02-05 15:42:27 +02:00

583 lines
21 KiB
C++

// ------------------------------------------------------------------------------------------------
#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 units
for (auto & u : m_Units)
{
u.second->Release();
}
// Release script objects held by classes
for (auto & c : m_Classes)
{
c.second->Release();
}
// Release script objects held by entries
for (auto & e : m_Entries)
{
e.second->Release();
}
// Release script objects held by the manager
Release();
// Clear the containers as well
m_Classes.clear();
m_Units.clear();
m_Entries.clear();
}
// ------------------------------------------------------------------------------------------------
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())
{
continue; // 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)
{
continue; // 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())
{
continue; // 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)
{
continue; // 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;
}
// ------------------------------------------------------------------------------------------------
void PvManager::RemoveEntryWithID(SQInteger id)
{
ModifyEntries();
// Remove this entry from the units
for (const auto & u : m_Units)
{
u.second->mPrivileges.erase(id);
}
// Remove this entry from the classes
for (const auto & c : m_Units)
{
c.second->mPrivileges.erase(id);
}
// Finally remove it from the list
m_Entries.erase(PvIdentity(id));
}
// ------------------------------------------------------------------------------------------------
void PvManager::RemoveEntryWithTag(StackStrF & tag)
{
ModifyEntries();
PvEntry & e = *GetValidEntryWithTag(tag);
// Remove this entry from the units
for (const auto & u : m_Units)
{
u.second->mPrivileges.erase(e.mID);
}
// Remove this entry from the classes
for (const auto & c : m_Units)
{
c.second->mPrivileges.erase(e.mID);
}
// Finally remove it from the list
auto itr = std::find_if(m_Entries.cbegin(), m_Entries.cend(),
[h = tag.CacheHash().GetHash()](PvEntry::List::const_reference e) -> bool { return e.first.mHash == h; });
// Was this unit found?
if (itr != m_Entries.end())
{
m_Entries.erase(itr);
}
}
// ------------------------------------------------------------------------------------------------
void PvManager::RemoveClassWithID(SqPvClass & sub, SQInteger id)
{
ModifyClasses();
PvClass::Ref cls = sub.mI.lock();
// Remove this entry from units
for (const auto & u : m_Units)
{
if (u.second->mClass.lock().get() == cls.get())
{
AutoAssign< bool > aag(m_LockUnits, false, true);
u.second->AssignClass(cls);
}
}
// Remove this entry from classes
for (const auto & c : m_Classes)
{
if (!c.second->mParent.expired() && c.second->mParent.lock().get() == cls.get())
{
AutoAssign< bool > aag(m_LockClasses, false, true);
c.second->AssignParent(cls);
}
}
// Finally remove it from the list
m_Classes.erase(PvIdentity(id));
}
// ------------------------------------------------------------------------------------------------
void PvManager::RemoveClassWithTag(SqPvClass & sub, StackStrF & tag)
{
ModifyClasses();
PvClass::Ref cls = sub.mI.lock();
// Remove this class from units
for (const auto & u : m_Units)
{
if (u.second->mClass.lock().get() == cls.get())
{
AutoAssign< bool > aag(m_LockUnits, false, true);
u.second->AssignClass(cls);
}
}
// Remove this class from classes
for (const auto & c : m_Classes)
{
if (!c.second->mParent.expired() && c.second->mParent.lock().get() == cls.get())
{
AutoAssign< bool > aag(m_LockClasses, false, true);
c.second->AssignParent(cls);
}
}
// Finally remove it from the list
auto itr = std::find_if(m_Classes.cbegin(), m_Classes.cend(),
[h = tag.CacheHash().GetHash()](PvClass::List::const_reference e) -> bool { return e.first.mHash == h; });
// Was this unit found?
if (itr != m_Classes.end())
{
m_Classes.erase(itr);
}
}
// ------------------------------------------------------------------------------------------------
void PvManager::RemoveUnitWithID(SQInteger id)
{
ModifyUnits();
// Remove this class from classes
for (const auto & c : m_Classes)
{
c.second->mUnits.erase(PvIdentity(id));
}
// Finally remove it from the list
m_Units.erase(PvIdentity(id));
}
// ------------------------------------------------------------------------------------------------
void PvManager::RemoveUnitWithTag(StackStrF & tag)
{
ModifyUnits();
PvUnit & u = *GetValidUnitWithTag(tag);
// Remove this class from classes
for (const auto & c : m_Classes)
{
c.second->mUnits.erase(PvIdentity(u.mID));
}
// Finally remove it from the list
auto itr = std::find_if(m_Units.cbegin(), m_Units.cend(),
[h = tag.CacheHash().GetHash()](PvUnit::List::const_reference e) -> bool { return e.first.mHash == h; });
// Was this unit found?
if (itr != m_Units.end())
{
m_Units.erase(itr);
}
}
// ------------------------------------------------------------------------------------------------
void PvManager::EachEntryID(Object & ctx, Function & func)
{
// Prevent any changes to entries during this operation
AutoAssign< bool > aag(m_LockEntries, false, true);
// Iterate entries and forward the ID to the callback
for (const auto & e : m_Entries)
{
func(ctx, e.second->mID);
}
}
// ------------------------------------------------------------------------------------------------
void PvManager::EachClassID(Object & ctx, Function & func)
{
// Prevent any changes to classes during this operation
AutoAssign< bool > aag(m_LockClasses, false, true);
// Iterate classes and forward the ID to the callback
for (const auto & c : m_Classes)
{
func(ctx, c.second->mID);
}
}
// ------------------------------------------------------------------------------------------------
void PvManager::EachUnitID(Object & ctx, Function & func)
{
// Prevent any changes to units during this operation
AutoAssign< bool > aag(m_LockUnits, false, true);
// Iterate units and forward the ID to the callback
for (const auto & u : m_Units)
{
func(ctx, u.second->mID);
}
}
// ------------------------------------------------------------------------------------------------
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)
.Func(_SC("RemoveUnit"), &PvManager::RemoveUnitWithID)
.FmtFunc(_SC("RemoveUnitWithTag"), &PvManager::RemoveUnitWithTag)
.Func(_SC("RemoveEntry"), &PvManager::RemoveEntryWithID)
.FmtFunc(_SC("RemoveEntryWithTag"), &PvManager::RemoveEntryWithTag)
.Func(_SC("RemoveClass"), &PvManager::RemoveClassWithID)
.FmtFunc(_SC("RemoveClassWithTag"), &PvManager::RemoveClassWithTag)
.FmtFunc(_SC("EachEntryID"), &PvManager::EachEntryID)
.FmtFunc(_SC("EachClassID"), &PvManager::EachClassID)
.FmtFunc(_SC("EachUnitID"), &PvManager::EachUnitID)
);
RootTable(vm).Bind(_SC("SqPrivilege"), ns);
}
} // Namespace:: SqMod