ff_i_persist
Persistent inventory functions.
Saves the inventory of a uniquely-tagged placeable or store to a campaign database, so its contents survive a restart.
The object’s tag is the key, which is why an object whose tag is shared with another is skipped rather than saved: two objects would overwrite each other.
Store items flagged infinite are never saved: the blueprint provides them again on load.
Once an object has been saved, its saved inventory replaces the toolset one on load: the toolset items are destroyed first (store infinite items are kept). Every save writes a marker row, so an emptied container stays empty after a restart instead of getting its toolset items back.
Warning
sTableName is used as an SQL table name and cannot be bound. Never pass
a value coming from player input.
-
FF_I_PERSIST_FLAG
Prefix of the delay flag that debounces a pending save.
-
string GetPersistFlag(string sSuffix)
- Parameters:
sSuffix – Campaign suffix, uppercased into the flag name.
- Returns:
FF_I_PERSIST_FLAGfollowed by “_” and the uppercased suffix.
Return the name of the delay flag for one persistence suffix.
-
void CreatePersistentDatabase(string sSuffix, string sTableName)
- Parameters:
sSuffix – Campaign suffix, appended to the campaign name.
sTableName – Name of the SQL table. Used verbatim.
Create the persistence table if it does not exist. Call once, at module load.
-
int LoadPersistentItems(object oObject, string sSuffix, string sTableName)
- Parameters:
oObject – An eligible placeable or store.
sSuffix – Campaign suffix, appended to the campaign name.
sTableName – Name of the SQL table. Used verbatim.
- Returns:
Number of saved items read. 0 if the tag is not unique or nothing was saved.
Restore oObject’s saved inventory from the campaign database. Does nothing if oObject’s tag is not unique, or if oObject was never saved. Otherwise the items already in the inventory (except store infinite items) are destroyed first, as the saved inventory replaces them.
-
void DestroyPersistentItems(object oObject, string sSuffix, string sTableName)
- Parameters:
oObject – An eligible placeable or store.
sSuffix – Campaign suffix, appended to the campaign name.
sTableName – Name of the SQL table. Used verbatim.
Drop oObject’s saved inventory from the campaign database. Does nothing if oObject’s tag is not unique.
-
void SavePersistentItems(object oObject, string sSuffix, string sTableName)
- Parameters:
oObject – An eligible placeable or store.
sSuffix – Campaign suffix, appended to the campaign name.
sTableName – Name of the SQL table. Used verbatim.
Save the current inventory of oObject to the campaign database. Debounced: the write happens three seconds after the call, and repeated calls in that window collapse into one. Does nothing if oObject’s tag is not unique. The item count is logged rather than returned, since the work is delayed.
Source code
// @code
#include "ff_i_expect"
#include "ff_i_campaign"
#include "ff_i_flags"
#include "nwnx_object"
//! @var FF_I_PERSIST_FLAG
//! @brief Prefix of the delay flag that debounces a pending save.
const string FF_I_PERSIST_FLAG = "__FF_I_PERSIST_FLAG";
// -----------------------------------------------------------------------------
//! @brief Return the name of the delay flag for one persistence suffix.
//! @param sSuffix Campaign suffix, uppercased into the flag name.
//! @return :cpp:var:`FF_I_PERSIST_FLAG` followed by "_" and the uppercased suffix.
string GetPersistFlag(string sSuffix);
string GetPersistFlag(string sSuffix)
{
return FF_I_PERSIST_FLAG + "_" + GetStringUpperCase(sSuffix);
}
// -----------------------------------------------------------------------------
//! @brief Create the persistence table if it does not exist. Call once, at module load.
//! @param sSuffix Campaign suffix, appended to the campaign name.
//! @param sTableName Name of the SQL table. Used verbatim.
void CreatePersistentDatabase(string sSuffix, string sTableName);
void CreatePersistentDatabase(string sSuffix, string sTableName)
{
string sCampaign = GetCampaignName(sSuffix);
string sSQL = "CREATE TABLE IF NOT EXISTS " + sTableName;
sSQL += " (tag TEXT NOT NULL, resref TEXT NON NULL, area TEXT NON NULL, object TEXT NOT NULL)";
sqlquery sqlQuery = SqlPrepareQueryCampaign(sCampaign, sSQL);
SqlStep(sqlQuery);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//! @brief Restore oObject's saved inventory from the campaign database.
//! Does nothing if oObject's tag is not unique, or if oObject was never saved. Otherwise
//! the items already in the inventory (except store infinite items) are destroyed first,
//! as the saved inventory replaces them.
//! @param oObject An eligible placeable or store.
//! @param sSuffix Campaign suffix, appended to the campaign name.
//! @param sTableName Name of the SQL table. Used verbatim.
//! @return Number of saved items read. 0 if the tag is not unique or nothing was saved.
int LoadPersistentItems(object oObject, string sSuffix, string sTableName);
int LoadPersistentItems(object oObject, string sSuffix, string sTableName)
{
if (!IsTagUnique(oObject))
return 0;
string sCampaign = GetCampaignName(sSuffix);
string sTag = GetStringLowerCase(GetTag(oObject));
// Never saved: keep the toolset inventory
sqlquery sqlQuery = SqlPrepareQueryCampaign(sCampaign, "SELECT COUNT(*) FROM " + sTableName + " WHERE tag = @sTag");
SqlBindString(sqlQuery, "@sTag", sTag);
if (!SqlStep(sqlQuery) || !SqlGetInt(sqlQuery, 0))
return 0;
// The saved inventory replaces the toolset one, otherwise both add up
_ClearPersistentItems(oObject);
// The marker row has an empty object
sqlQuery = SqlPrepareQueryCampaign(sCampaign, "SELECT object FROM " + sTableName + " WHERE tag = @sTag AND object != ''");
SqlBindString(sqlQuery, "@sTag", sTag);
int nCount = 0;
while (SqlStep(sqlQuery))
{
object oItem = NWNX_Object_Deserialize(SqlGetString(sqlQuery, 0));
if (GetIsObjectValid(oItem))
{
CopyItem(oItem, oObject, TRUE);
DestroyObject(oItem);
}
nCount++;
}
return nCount;
}
// -----------------------------------------------------------------------------
//! @brief Drop oObject's saved inventory from the campaign database.
//! Does nothing if oObject's tag is not unique.
//! @param oObject An eligible placeable or store.
//! @param sSuffix Campaign suffix, appended to the campaign name.
//! @param sTableName Name of the SQL table. Used verbatim.
void DestroyPersistentItems(object oObject, string sSuffix, string sTableName);
void DestroyPersistentItems(object oObject, string sSuffix, string sTableName)
{
if (!IsTagUnique(oObject))
return;
string sCampaign = GetCampaignName(sSuffix);
string sTag = GetStringLowerCase(GetTag(oObject));
sqlquery sqlQuery = SqlPrepareQueryCampaign(sCampaign, "DELETE FROM " + sTableName + " WHERE TAG = @sTag");
SqlBindString(sqlQuery, "@sTag", sTag);
SqlStep(sqlQuery);
}
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
//! @brief Save the current inventory of oObject to the campaign database.
//! Debounced: the write happens three seconds after the call, and repeated calls in that window
//! collapse into one. Does nothing if oObject's tag is not unique. The item count is
//! logged rather than returned, since the work is delayed.
//! @param oObject An eligible placeable or store.
//! @param sSuffix Campaign suffix, appended to the campaign name.
//! @param sTableName Name of the SQL table. Used verbatim.
void SavePersistentItems(object oObject, string sSuffix, string sTableName);
void SavePersistentItems(object oObject, string sSuffix, string sTableName)
{
if (!IsTagUnique(oObject))
return;
// We only save every 3 seconds
SetDelayFlag(oObject, GetPersistFlag(sSuffix));
DelayCommand(3.0f, _SavePersistentItems(oObject, sSuffix, sTableName));
}