mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-08 08:47:17 +01:00
667 lines
24 KiB
C++
667 lines
24 KiB
C++
#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); }
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a entry with a certain identifier from this manager.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetEntryWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a entry with a certain tag from this manager.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetEntryWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* See if a entry with a certain identifier exists in this manager.
|
|
*/
|
|
bool HaveEntryWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* See if a entry with a certain tag exists in this manager.
|
|
*/
|
|
bool HaveEntryWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a class with a certain identifier from this manager.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetClassWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a class with a certain tag from this manager.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetClassWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* See if a class with a certain identifier exists in this manager.
|
|
*/
|
|
bool HaveClassWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* See if a class with a certain tag exists in this manager.
|
|
*/
|
|
bool HaveClassWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a unit with a certain identifier from this manager.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetUnitWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Retrieve a unit with a certain tag from this manager.
|
|
*/
|
|
SQMOD_NODISCARD LightObj GetUnitWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* See if a unit with a certain identifier exists in this manager.
|
|
*/
|
|
bool HaveUnitWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* See if a unit with a certain tag exists in this manager.
|
|
*/
|
|
bool HaveUnitWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Remove a entry with a certain identifier from this manager.
|
|
*/
|
|
void RemoveEntryWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Remove a entry with a certain tag from this manager.
|
|
*/
|
|
void RemoveEntryWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Remove a class with a certain identifier from this manager.
|
|
*/
|
|
void RemoveClassWithID(SqPvClass & sub, SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Remove a class with a certain tag from this manager.
|
|
*/
|
|
void RemoveClassWithTag(SqPvClass & sub, StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Remove a unit with a certain identifier from this manager.
|
|
*/
|
|
void RemoveUnitWithID(SQInteger id);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Remove a unit with a certain tag from this manager.
|
|
*/
|
|
void RemoveUnitWithTag(StackStrF & tag);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Invoke a given callback with every known entry identifier.
|
|
*/
|
|
void EachEntryID(Object & ctx, Function & func);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Invoke a given callback with every known class identifier.
|
|
*/
|
|
void EachClassID(Object & ctx, Function & func);
|
|
|
|
/* --------------------------------------------------------------------------------------------
|
|
* Invoke a given callback with every known unit identifier.
|
|
*/
|
|
void EachUnitID(Object & ctx, Function & func);
|
|
};
|
|
|
|
} // Namespace:: SqMod
|