ff_u_gc_plc

Placeable garbage collector.

Destroys placeables that have been in the world longer than GC_PLC_DURATION game hours and whose area has no players in it.

Variables

ENABLE__FF_U_GC_PLC: (string) (opt-out) Set to "N" to disable unit.

GC_PLC_DURATION: (int) Maximum age in module game hours before a placeable is destroyed. Defaults to 7 days.

Source code

// @code

#include "ff_i_core"


const string ENABLE__FF_U_GC_PLC = "ENABLE__FF_U_GC_PLC";

const string ARRAY_NAME = "__FF_U_GC_PLC__ARRAY";

const string GC_PLC_TIMESTAMP = "__FF_U_GC_PLC__TIMESTAMP";

const string GC_PLC_DURATION = "GC_PLC_DURATION";

const int DEFAULT_DURATION = 7 * 24 * 60; // 7 days

const string GARBAGE_COLLECT = "GARBAGE_COLLECT";


// -----------------------------------------------------------------------------

//! @brief Return TRUE if oObject is a non-static placeable with inventory and the GARBAGE_COLLECT flag set.
//! @param oObject An object.
int IsEligible(object oObject);
int IsEligible(object oObject)
{
  if (!GetObjectFlag(oObject, GARBAGE_COLLECT))
    return FALSE;

  int nObjectType = GetObjectType(oObject);
  if (nObjectType != OBJECT_TYPE_PLACEABLE)
    return FALSE;

  if (NWNX_Object_GetPlaceableIsStatic(oObject))
    return FALSE;

  if (!GetHasInventory(oObject))
    return FALSE;

  return TRUE;
}


// -----------------------------------------------------------------------------

//! @brief Remove the GC timestamp from oObject.
//! @param oObject A tracked item.
void UntrackItem(object oObject);
void UntrackItem(object oObject)
{
  DeleteLocalInt(oObject, GC_PLC_TIMESTAMP);
}


// -----------------------------------------------------------------------------

//! @brief Destroy items in oPlaceable that have exceeded GC_PLC_DURATION.
//! @param oPlaceable An eligible placeable.
void DeleteItems(object oPlaceable);
void DeleteItems(object oPlaceable)
{
  int nNow = GetTimeStamp();

  object oItem = GetFirstItemInInventory(oPlaceable);
  while (GetIsObjectValid(oItem))
  {
    int nStart = GetLocalInt(oItem, GC_PLC_TIMESTAMP);
    if (nStart == 0)
      SetLocalInt(oItem, GC_PLC_TIMESTAMP, GetTimeStamp());
    else
    {
      int nMaxAge = GetRecursiveInt(oPlaceable, GC_PLC_DURATION, DEFAULT_DURATION);
      nMaxAge = max(nMaxAge, 1);
      nMaxAge = nMaxAge * 60;

      int nSeconds = nNow - nStart;
      if (nSeconds > 0 && nSeconds >= nMaxAge)
      {
        LogInfo("Placeable Garbage Collector: Removal of " + GetObjectInfo(oItem)
          + " (age: " + IntToString(nSeconds)
          + ", max age: " + IntToString(nMaxAge) + ")");
        DestroyObject(oItem, 0.0f);
      }
    }
    oItem = GetNextItemInInventory(oItem);
  }

}

// -----------------------------------------------------------------------------

//! @brief Stamp a GC timestamp on every untracked item in oPlaceable.
//! @param oPlaceable An eligible placeable.
void TrackItems(object oPlaceable);
void TrackItems(object oPlaceable)
{
  object oItem = GetFirstItemInInventory(oPlaceable);
  while (GetIsObjectValid(oItem))
  {
    if (!GetLocalInt(oItem, GC_PLC_TIMESTAMP))
      SetLocalInt(oItem, GC_PLC_TIMESTAMP, GetTimeStamp());
    oItem = GetNextItemInInventory(oItem);
  }
}

// -----------------------------------------------------------------------------

void main()
{
  object oModule = GetModule();
  if (!GetModuleFlag(ENABLE__FF_U_GC_PLC, TRUE))
    return;

  string sEvent = GetCurrentEvent();
  if (sEvent == ON_REGISTER)
  {
    SubscribeToEvent(ON_DEFAULT_ITEM_ACQUIRE, __FILE__);
    SubscribeToEvent(ON_AFTER_PLACEABLE_CLOSE, __FILE__);
    SubscribeToEvent(ON_BEFORE_PLACEABLE_OPEN, __FILE__);
  }
  else if (sEvent == ON_DEFAULT_ITEM_ACQUIRE)
    UntrackItem(GetModuleItemAcquired());
  else if (sEvent == ON_BEFORE_PLACEABLE_OPEN && IsEligible(OBJECT_SELF))
    DeleteItems(OBJECT_SELF);
  else if (sEvent == ON_AFTER_PLACEABLE_CLOSE && IsEligible(OBJECT_SELF))
    TrackItems(OBJECT_SELF);
}