CampaignObject either not being stored or retrieved from DB correctly

First time using DB functions, so please forgive me if this is elementary.

My ultimate goal is to be able to pass variables and items persistently between characters on the same ‘account’ (via either GetPCPlayerName or GetPublicCDKey).

My thought was to pass an item, with the variables I need stored on it, between characters. It would be easy enough to modify a persistent storage chest system to accomplish this. But I’m not sure if items maintain local variables when passed through the database.

I added code to my Mod_OnEnter script to test that. Problem is, it never seems to retrieve a valid object. It creates the campaign token in my inventory, reports it created it, then reports it stored it. I exit and return with the same character, and get the same output (instead of telling me the token has been retrieved and reporting the value of the stored variable, as it should). So… it’s always returning OBJECT_INVALID.

Would like to understand what is wrong here - I’m sure it’s probably something simple I’m missing.

Am also open to suggestions for implementing persistent variable passing across multiple chars on the same player account. This is for an account-wide achievement system that would not need to be accessed often during play. I had hoped to be able to store all variables on an item and do a single DB transaction with the item instead of storing all the variables separately in the DB, but don’t have enough experience with the DB functionality (or it’s resource intensiveness) to know what’s best practice.

void main()
{
object oPC = GetEnteringObject();

// exit script if entering object is not a PC
if (!GetIsPC(oPC)) return;


// TESTING - persistent variables on items passed through DB
object oCampaignToken = RetrieveCampaignObject("dddcampaign", "campaigntoken", GetLocation(oPC), oPC);
if (oCampaignToken == OBJECT_INVALID)
    {
    DestroyCampaignDatabase("dddcampaign");
    oCampaignToken = CreateItemOnObject("campaigntoken", oPC);
    FloatingTextStringOnCreature("Campaign Token Created", oPC);
    SetLocalInt(oCampaignToken, "testvalue", 5);
    if (StoreCampaignObject("dddcampaign", "campaigntoken", oCampaignToken))
        FloatingTextStringOnCreature("Campaign Token Stored", oPC);
    }
else
    {
    int iTV = GetLocalInt(oCampaignToken, "testvalue");
    FloatingTextStringOnCreature("Campaign Token Retrieved", oPC);
    FloatingTextStringOnCreature(IntToString(iTV), oPC);
    }

I did some research and your problem seems to originate from here:

object oCampaignToken = RetrieveCampaignObject("dddcampaign", "campaigntoken", GetLocation(oPC), oPC);

or - more precisely - from here:

GetLocation(oPC)

Location of PC (or any object other than area or module) is undefined unless they are in an area. However module’s on enter handler is called prior to that so GetLocation(oPC) returns invalid location causing RetrieveCampaignObject in your script to always return OBJECT_INVALID. You can test this by adding the following code to your script, then the check game’s log.

if(GetIsObjectValid(GetAreaFromLocation(GetLocation(oPC))))
{
    PrintString(GetName(oPC) + "'s location is valid");
}
else
{
    PrintString(GetName(oPC) + "'s location is NOT valid");
}

As a solution, I suggest you move your code to area’s on enter handler. All of them, unfortunately.

1 Like

Ok, that makes sense. Since the item is going to oPC’s inventory anyway, the Location argument is actually redundant anyway. Perhaps any valid Location will work.

Will fiddle more and report back.

Thanks for getting me unstuck.

Actually the problem listed by NWShaker is correct but the ia a second issue. Your trying to store an object, but a location is not an object…a location contains an area object though. You need to retrieve the area object from the location using GetAreaFromLocation() function.

object oCampaignToken = RetrieveCampaignObject(“dddcampaign”, “campaigntoken”, GetAreaFromLocation(GetLocation(oPC)), oPC);

1 Like

Not sure I follow. The third argument of the RetrieveCampaignObject command calls for a Location, not an Object. It’s used to tell the game where to create the object if it’s not being created in an inventory (or can’t fit in that inventory).

The object being retrieved is pointed to by the “campaigntoken” string, as established in the StoreCampaignObject command.

Oops, Never mind my post, hehe. I should read my notes more thoroughly. Gibberish, nothing but gibberish… :embarrassed:

Nah, don’t be embarrassed. This stuff is fairly complex, and it’s not so easy to grasp all the details by just reading a post. I struggled with this for hours last night. I’ve stared at that patch of code long enough to see it in my sleep (literally). But before yesterday, I would’ve had to refer to the lexicon to even be able to interpret that same code.

I apologize if I came off as condescending. Not my intent. I think it’s great if people feel empowered to give input, even if it’s sometimes in error. Sometimes it can still help. And an environment where nobody posts anything because they are afraid of being wrong just leads to a ghost forum.

As an aside - PC location isn’t defined OnEnter to an area, either.

It seems to be set immediately after OnEnter completes.

Did you manage to fix it? It’s possible that all locations are invalid at that point since areas may be still uninitialized. Then again, if item is spawned in somebody’s backpack, then why the game would bother with it’s location? Perhaps location check goes first and since it fails, the whole function fails. More research would be useful to resolve this:

The same page also has a warning, which may be related to second part of your post:

I made another experiment and the location is available in OnEnter there, so perhaps it’s a timing issue. Same problem happens when you try to work with carmours too soon. The only way to be sure is to nuke it from orbit use a ~1s DelayCommand.

Yep, it worked! The invalid location was the problem. Instead of using oPC’s location I used the location of the only NPC in the area. Probably any object in the area would’ve worked other than the PC.

Also, the floaty-text outputted test value (iTV in my script) was 5. So items DO retain variables across database transactions. At least integers - haven’t tried other data types.

I had also saw that note on the Lexicon page about local variables being lost but had reason to doubt it was true. It may well have been true in earlier game versions, but it appears to now be outdated.

Using a waypoint object is probably the safest way (NPCs may eventually disappear).

Good job with the research anyway. I believe it is safe to assume that local string and float variables will be saved as well. Locations probably too. No idea about objects, though.

As for the variable carrier - you may want to use PC’s creature hide (carmour) to avoid carrying any immersion-breaking, undroppable items. It will also allow you to i.e. retain extra feat bonuses between the characters. Then you just need to make a small modification to Set/Get/DeleteLocalX function family.

I’ve been implementing my challenge system in earnest, and wanted to update with some info.

You can save a store object to the database. When retrieved from the db, it will retain all items that were in it at the time it was saved. Those items also retain any variables placed on them.

IMO, utilizing this can make the built-in db a pretty good option for some things. Variables can be subject to two layers of organization in the db (you can put sets of variables on ‘token’ items to organize them, and further organize them by placing those tokens into various stores). Best of all, the db transaction itself is simple to code, as all you are saving/retrieving is a few store objects. This makes it much less fiddly and more stable (in theory).