ff_u_gc_area
Area garbage collector.
Variables
ENABLE__FF_U_GC_AREA: (string) (opt-out) Set to “N” to disable unit.
GC_AREA_DURATION: (int) Maximum age in module game hours before a corpse or loose item is destroyed in an empty area. Defaults to 24.
Source code
// @code
#include "ff_i_core"
// -----------------------------------------------------------------------------
const string ENABLE__FF_U_GC_AREA = "ENABLE__FF_U_GC_AREA";
const string ARRAY_NAME = "__FF_U_GC_AREA__ARRAY";
const string GC_AREA_TIMESTAMP = "__FF_U_GC_AREA__TIMESTAMP";
const string GC_AREA_DURATION = "GC_AREA_DURATION";
const int DEFAULT_DURATION = 20;
// -----------------------------------------------------------------------------
void _TrackItem(object oObject)
{
ObjectArrayAdd(ARRAY_NAME, oObject);
SetLocalInt(oObject, GC_AREA_TIMESTAMP, GetTimeStamp());
}
//! @brief Start tracking oObject for area garbage collection if eligible.
//! @param oObject An item or BodyBag placeable.
void TrackItem(object oObject);
void TrackItem(object oObject)
{
if (!GetIsObjectValid(oObject))
return;
object oPossessor = GetItemPossessor(oObject);
int nType = GetObjectType(oObject);
// Keep all items with the tag BodyBag,
// Keep all items on the ground.
if (nType == OBJECT_TYPE_ITEM && (GetIsObjectValid(oPossessor) == FALSE))
_TrackItem(oObject);
else if (nType == OBJECT_TYPE_PLACEABLE && (GetTag(oObject) == TAG_BODY_BAG))
_TrackItem(oObject);
else if (nType == OBJECT_TYPE_ITEM && (GetTag(oPossessor) == TAG_BODY_BAG))
{
object oItem = GetFirstItemInInventory(oPossessor);
while (GetIsObjectValid(oItem))
{
_TrackItem(oItem);
oItem = GetNextItemInInventory(oPossessor);
}
}
}
// -----------------------------------------------------------------------------
//! @brief Remove oObject from area GC tracking.
//! @param oObject A tracked object.
void UntrackItem(object oObject);
void UntrackItem(object oObject)
{
if (!GetIsObjectValid(oObject))
return;
ObjectArrayDelete(ARRAY_NAME, oObject);
DeleteLocalInt(oObject, GC_AREA_TIMESTAMP);
}
// -----------------------------------------------------------------------------
//! @brief Track all placeables and creatures within 5m of lWhere.
//! @param lWhere Centre of the search sphere.
void TrackFromLocation(location lWhere);
void TrackFromLocation(location lWhere)
{
// Mark the location for later.
object oObject = GetFirstObjectInShape(SHAPE_SPHERE, 5.0f, lWhere, FALSE, OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_CREATURE);
while (GetIsObjectValid(oObject))
{
TrackItem(oObject);
oObject = GetNextObjectInShape(SHAPE_SPHERE, 5.0f, lWhere, FALSE, OBJECT_TYPE_PLACEABLE | OBJECT_TYPE_CREATURE);
}
}
// -----------------------------------------------------------------------------
void OnRealtimeMinute();
void OnRealtimeMinute()
{
object oModule = GetModule();
int nNow = GetTimeStamp();
sqlquery sqlQuery = ObjectArrayIterate(ARRAY_NAME);
while (SqlStep(sqlQuery))
{
string sUUID = SqlGetString(sqlQuery, 0);
object oItem = GetObjectByUUID(sUUID);
if (!GetIsObjectValid(oItem))
{
ObjectArrayDelete(ARRAY_NAME, oItem);
continue;
}
int nStart = GetLocalInt(oItem, GC_AREA_TIMESTAMP);
if (nStart == 0)
{
SetLocalInt(oItem, GC_AREA_TIMESTAMP, GetTimeStamp());
continue;
}
int nMaxAge = GetRecursiveInt(oItem, GC_AREA_DURATION, DEFAULT_DURATION);
nMaxAge = max(nMaxAge, 1);
nMaxAge = nMaxAge * 60; // in minutes
int nSeconds = nNow - nStart;
if (nSeconds > 0 && nSeconds >= nMaxAge)
{
LogInfo("Area Garbage Collector: Removal of " + GetObjectInfo(oItem)
+ " (age: " + IntToString(nSeconds)
+ ", max age: " + IntToString(nMaxAge) + ")");
ObjectArrayDelete(ARRAY_NAME, oItem);
DestroyInventory(oItem, 0.0f);
DestroyObject(oItem, 0.1f);
}
}
}
// -----------------------------------------------------------------------------
void OnConsole();
void OnConsole()
{
object oModule = GetModule();
string sCommand = GetLocalString(oModule, CONSOLE_COMMAND);
string sCommandLine = GetLocalString(oModule, CONSOLE_ARGS);
struct CLI_ARGUMENTS sArgs = GetArguments(sCommand + " " + sCommandLine);
int nTime = StringToInt(sArgs.sArg1);
if (nTime == 0 && (sArgs.sArg1 == ""))
nTime = -1;
OnRealtimeMinute();
}
// -----------------------------------------------------------------------------
void main()
{
object oModule = GetModule();
if (!GetModuleFlag(ENABLE__FF_U_GC_AREA, TRUE))
return;
string sEvent = GetCurrentEvent();
if (sEvent == ON_REGISTER)
{
CreateObjectArray(ARRAY_NAME);
// RegisterConsoleCommand("gc", __FILE__); FIXME/TODO
SubscribeToEvent(ON_DEFAULT_OBJECT_DEATH, __FILE__);
SubscribeToEvent(ON_DEFAULT_ITEM_ACQUIRE, __FILE__);
SubscribeToEvent(ON_DEFAULT_ITEM_LOST, __FILE__);
SubscribeToEvent(ON_REALTIME_MINUTE, __FILE__);
SubscribeToEvent(ON_CONSOLE_COMMAND_HELP, __FILE__);
}
else if (sEvent == ON_DEFAULT_ITEM_ACQUIRE)
UntrackItem(GetModuleItemAcquired());
else if (sEvent == ON_DEFAULT_ITEM_LOST)
TrackItem(GetModuleItemLost());
else if (sEvent == ON_REALTIME_MINUTE)
OnRealtimeMinute();
else if (sEvent == ON_DEFAULT_CREATURE_DEATH || sEvent == ON_DEFAULT_OBJECT_DEATH)
{
object oObject = OBJECT_SELF; // technically, not a PC
location lObject = GetLocation(oObject);
AssignCommand(GetArea(oObject), DelayCommand(10.0f, TrackFromLocation(lObject)));
}
//else if (sEvent == ON_CONSOLE_COMMAND_HELP)
// NWNX_Util_RawPrint(GetStringRightPad("gc AREA TIME", CONSOLE_HELP_PAD) + "- Run garbage collector");
else
OnConsole();
}