Well, I've got a workaround for now, but I'm not a big fan of it. Still searching for the root cause. But anyway - the following is in a batch file scheduled to run every 15 minutes. This provides file system redundacy to provide a mostly up-to-date backup the property database. I guess it could be run even more often as it's pretty lightweight and the files (in my case) that are being copied are barely over 1 MB.
@echo off
:: variables
set drive=C:\NeverwinterNights\NWN\database
set backupcmd=copy /y
echo ### Backing up database...
%backupcmd% "%drive%\HH_PROPERTY.CDX" "%drive%\HH_PROPERTY_COPY.CDX"
%backupcmd% "%drive%\HH_PROPERTY.DBF" "%drive%\HH_PROPERTY_COPY.DBF"
%backupcmd% "%drive%\HH_PROPERTY.FPT" "%drive%\HH_PROPERTY_COPY.FPT"
echo Backup Complete!
After that, I ended up modifying the NBDE_GetCampaignDatabaseObject to look like this (the only change being the 7 lines below "// not found ? create it"):
// returns database object for the specified campaign database
//
// - auto-creates database object in case it doesn't exist
// - builds index for fast access
//
// you usually don't need to use this function directly...
object NBDE_GetCampaignDatabaseObject(string sCampaignName)
{
// get database item
object oDatabase = GetLocalObject(GetObjectByTag(NBDE_VAULT_TAG), NBDE_INDEX_PREFIX + sCampaignName);
// retrieve/create database if not indexed already
if(!GetIsObjectValid(oDatabase))
{
// get database vault object
// this container holds all database objects/items
object oVault = GetObjectByTag(NBDE_VAULT_TAG);
// check for valid vault
if(!GetIsObjectValid(oVault))
{
WriteTimestampedLogEntry("NBDE> Error: unable to locate '"+NBDE_VAULT_TAG+"' vault container object");
return OBJECT_INVALID;
}
// one time load
oDatabase = RetrieveCampaignObject(sCampaignName, NBDE_DATABASE_ITEM_VARNAME, GetLocation(oVault), oVault);
// not found ? create it
//if(!GetIsObjectValid(oDatabase)) oDatabase = CreateItemOnObject(NBDE_DATABASE_ITEM_RESREF, oVault);
//Thayan modification for redundancy check. Need to have an OS batch file setup to make the database copy for this to work
if(!GetIsObjectValid(oDatabase)) {
oDatabase = RetrieveCampaignObject(sCampaignName+"_COPY", NBDE_DATABASE_ITEM_VARNAME, GetLocation(oVault), oVault);
if(!GetIsObjectValid(oDatabase)) oDatabase = CreateItemOnObject(NBDE_DATABASE_ITEM_RESREF, oVault) ;
else WriteTimestampedLogEntry("NBDE> Error: unable to retrieve '"+sCampaignName+"' database. Created from _COPY backup.");
}
// check for valid database object
if(!GetIsObjectValid(oDatabase))
{
WriteTimestampedLogEntry("NBDE> Error: unable to create '"+sCampaignName+"' database object");
return OBJECT_INVALID;
}
// index item for fast access
SetLocalObject(oVault, NBDE_INDEX_PREFIX + sCampaignName, oDatabase);
}
return oDatabase;
}
I'm definitely not real happy about this workaround/redundancy option, and if anyone has better recommendations I'd love to hear them. But for now I guess it at least (mostly) masks the problem and, at worst, would mean 'only' 15 minutes of lost data if it ends up falling back to the database copy files.