ff_i_gc

Inventory and object garbage collection.

Stamps a real-world timestamp on an object, then tells when it is older than an age limit. The caller names the timestamp and age-limit variables, so each garbage collector keeps its own clock. The placeable, store and area recreation garbage collectors (ff_u_plc_gc, ff_u_store_gc, ff_u_area_create) are built on it.

For containers, every item of the inventory is stamped, and the items older than the container’s age limit are destroyed. Store items flagged infinite are never stamped or destroyed: the store keeps providing them.

void TrackGCObject(object oObject, string sTimestampVar)
Parameters:
  • oObject – Any object: item, area…

  • sTimestampVar – Local int on oObject that holds the tracking timestamp.

Stamp a GC timestamp on oObject, if it is not already tracked. The clock of an already tracked object is not reset.

void UntrackGCObject(object oObject, string sTimestampVar)
Parameters:
  • oObject – Any object: item, area…

  • sTimestampVar – Local int on oObject that holds the tracking timestamp.

Remove the GC timestamp from oObject. Does nothing before ON_MODULE_START, or if the object is not tracked.

int GetGCMaxAge(object oObject, string sDurationVar, int nDefaultDuration, int nUnit = 60)
Parameters:
  • oObject – The object holding the limit, or its area or module.

  • sDurationVar – Variable holding the age limit, in units.

  • nDefaultDuration – Age limit used when sDurationVar is unset, in units.

  • nUnit – Seconds per unit: 60 for minutes (default), 3600 for hours.

Returns:

The age limit, in seconds, at least nUnit.

Return the age limit, in seconds, read recursively from oObject. The limit is read from oObject, its area, then the module, in units of nUnit seconds (minutes by default), and is floored to 1 unit.

int GetGCAge(object oObject, string sTimestampVar)
Parameters:
  • oObject – Any object: item, area…

  • sTimestampVar – Local int on oObject that holds the tracking timestamp.

Returns:

The age, or 0 if oObject is not tracked.

Return the age of oObject since it was tracked, in seconds.

int GetGCObjectExpired(object oObject, string sTimestampVar, int nMaxAge)
Parameters:
  • oObject – Any object: item, area…

  • sTimestampVar – Local int on oObject that holds the tracking timestamp.

  • nMaxAge – Age limit, in seconds, see GetGCMaxAge().

Returns:

TRUE if expired, FALSE otherwise.

Return TRUE if oObject is tracked and at least nMaxAge seconds old.

void TrackGCInventory(object oObject, string sTimestampVar)
Parameters:
  • oObject – A container: placeable or store.

  • sTimestampVar – Local int on each item that holds the tracking timestamp.

Stamp a GC timestamp on every untracked item in oObject’s inventory. Items already carrying the stamp are left as they are, so the clock is not reset.

void DeleteGCItems(object oObject, string sTimestampVar, string sDurationVar, int nDefaultDuration, int nUnit = 60)
Parameters:
  • oObject – A container: placeable or store.

  • sTimestampVar – Local int on each item that holds the tracking timestamp.

  • sDurationVar – Variable holding the age limit, in units.

  • nDefaultDuration – Age limit used when sDurationVar is unset, in units.

  • nUnit – Seconds per unit: 60 for minutes (default), 3600 for hours.

Destroy items in oObject older than their per-container age limit. An untracked item is stamped rather than destroyed, so it gets a full lifetime from first sight. The age limit is read recursively (container, area, module) and is in units of nUnit seconds (minutes by default), floored to 1.

Source code

// @code

#include "ff_i_console"
#include "ff_i_object"
#include "ff_i_datetime"
#include "ff_i_flags"

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

//! @brief Stamp a GC timestamp on oObject, if it is not already tracked.
//! The clock of an already tracked object is not reset.
//! @param oObject Any object: item, area...
//! @param sTimestampVar Local int on oObject that holds the tracking timestamp.
void TrackGCObject(object oObject, string sTimestampVar);
void TrackGCObject(object oObject, string sTimestampVar)
{
  if (GetLocalInt(oObject, sTimestampVar))
    return;

  LogDebug(__FILE__, "Tracking " + GetObjectInfo(oObject) + " in " + sTimestampVar);
  SetLocalInt(oObject, sTimestampVar, GetTimeStamp());
}


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

//! @brief Remove the GC timestamp from oObject.
//! Does nothing before :cpp:var:`ON_MODULE_START`, or if the object is not tracked.
//! @param oObject Any object: item, area...
//! @param sTimestampVar Local int on oObject that holds the tracking timestamp.
void UntrackGCObject(object oObject, string sTimestampVar);
void UntrackGCObject(object oObject, string sTimestampVar)
{
  // Refused before the module has started, so the sweep does not fire on
  // inventories still being populated at load.
  if (!GetLocalInt(GetModule(), ON_MODULE_START))
    return;

  if (GetLocalInt(oObject, sTimestampVar))
  {
    LogDebug(__FILE__, "Untracking " + GetObjectInfo(oObject) + " from " + sTimestampVar);
    DeleteLocalInt(oObject, sTimestampVar);
  }
}


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

//! @brief Return the age limit, in seconds, read recursively from oObject.
//! The limit is read from oObject, its area, then the module, in units of nUnit
//! seconds (minutes by default), and is floored to 1 unit.
//! @param oObject The object holding the limit, or its area or module.
//! @param sDurationVar Variable holding the age limit, in units.
//! @param nDefaultDuration Age limit used when sDurationVar is unset, in units.
//! @param nUnit Seconds per unit: 60 for minutes (default), 3600 for hours.
//! @return The age limit, in seconds, at least nUnit.
int GetGCMaxAge(object oObject, string sDurationVar, int nDefaultDuration, int nUnit = 60);
int GetGCMaxAge(object oObject, string sDurationVar, int nDefaultDuration, int nUnit = 60)
{
  int nMaxAge = GetRecursiveInt(oObject, sDurationVar, nDefaultDuration);
  nMaxAge = max(nMaxAge, 1);
  return nMaxAge * nUnit; // Units to seconds
}


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

//! @brief Return the age of oObject since it was tracked, in seconds.
//! @param oObject Any object: item, area...
//! @param sTimestampVar Local int on oObject that holds the tracking timestamp.
//! @return The age, or 0 if oObject is not tracked.
int GetGCAge(object oObject, string sTimestampVar);
int GetGCAge(object oObject, string sTimestampVar)
{
  int nStart = GetLocalInt(oObject, sTimestampVar);
  if (nStart == 0)
    return 0;
  return GetTimeStamp() - nStart;
}


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

//! @brief Return TRUE if oObject is tracked and at least nMaxAge seconds old.
//! @param oObject Any object: item, area...
//! @param sTimestampVar Local int on oObject that holds the tracking timestamp.
//! @param nMaxAge Age limit, in seconds, see GetGCMaxAge().
//! @return TRUE if expired, FALSE otherwise.
int GetGCObjectExpired(object oObject, string sTimestampVar, int nMaxAge);
int GetGCObjectExpired(object oObject, string sTimestampVar, int nMaxAge)
{
  int nSeconds = GetGCAge(oObject, sTimestampVar);
  return (nSeconds > 0 && nSeconds >= nMaxAge);
}


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

//! @brief Return TRUE if oItem, in a container of type nObjectType, is never tracked.
//! Store items flagged infinite are provided again by the blueprint.
//! @param oItem An item.
//! @param nObjectType The OBJECT_TYPE_* of the item's container.
//! @return TRUE if the item is ignored by the garbage collector.
int _GetIsGCIgnored(object oItem, int nObjectType)
{
  return (nObjectType == OBJECT_TYPE_STORE) && GetInfiniteFlag(oItem);
}


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

//! @brief Stamp a GC timestamp on every untracked item in oObject's inventory.
//! Items already carrying the stamp are left as they are, so the clock is not reset.
//! @param oObject A container: placeable or store.
//! @param sTimestampVar Local int on each item that holds the tracking timestamp.
void TrackGCInventory(object oObject, string sTimestampVar);
void TrackGCInventory(object oObject, string sTimestampVar)
{
  int nObjectType = GetObjectType(oObject);

  object oItem = GetFirstItemInInventory(oObject);
  while (GetIsObjectValid(oItem))
  {
    if (!_GetIsGCIgnored(oItem, nObjectType))
      TrackGCObject(oItem, sTimestampVar);
    oItem = GetNextItemInInventory(oObject);
  }
}


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

//! @brief Destroy items in oObject older than their per-container age limit.
//! An untracked item is stamped rather than destroyed, so it gets a full lifetime from
//! first sight. The age limit is read recursively (container, area, module) and
//! is in units of nUnit seconds (minutes by default), floored to 1.
//! @param oObject A container: placeable or store.
//! @param sTimestampVar Local int on each item that holds the tracking timestamp.
//! @param sDurationVar Variable holding the age limit, in units.
//! @param nDefaultDuration Age limit used when sDurationVar is unset, in units.
//! @param nUnit Seconds per unit: 60 for minutes (default), 3600 for hours.
void DeleteGCItems(object oObject, string sTimestampVar, string sDurationVar, int nDefaultDuration, int nUnit = 60);
void DeleteGCItems(object oObject, string sTimestampVar, string sDurationVar, int nDefaultDuration, int nUnit = 60)
{
  int nObjectType = GetObjectType(oObject);
  int nMaxAge = GetGCMaxAge(oObject, sDurationVar, nDefaultDuration, nUnit);

  object oItem = GetFirstItemInInventory(oObject);
  while (GetIsObjectValid(oItem))
  {
    if (_GetIsGCIgnored(oItem, nObjectType))
      { /* never tracked */ }
    else if (!GetLocalInt(oItem, sTimestampVar))
      TrackGCObject(oItem, sTimestampVar);
    else if (GetGCObjectExpired(oItem, sTimestampVar, nMaxAge))
    {
      LogInfo(__FILE__ + ": Removal of " + GetObjectInfo(oItem)
        + " (age: " + IntToString(GetGCAge(oItem, sTimestampVar))
        + ", max age: " + IntToString(nMaxAge) + ")");
      DestroyObject(oItem, 0.0f);
    }
    oItem = GetNextItemInInventory(oObject);
  }
}