Saving Location?

Hi there,
I have been grappling with trying to save a Location - specifically the player’s location onClientExit so they can be put back into their old spot onClientEnter rather than the module start location. The problem I’ve run up against is that there’s no interface for location objects with SQL. Now, I can unpack a location into it’s three components - oArea, vPosition, and fFacing - but then loading the oArea thing wants me to have a location I’m spawning it in, which seems a little like asking me to have a chicken so I can have an egg.

Anyone able to lend some insight into how to accomplish this without increasing my blood cortisol levels any higher?

  • May

You can save the area tag as a string and then get the object when you need it onClientEnter.

Usually (or at least in the past) the vector is also split up in the x y z coordinates at least for mySQL use with nwnx. The shiny new in box SQL thingy probably does have that concept already so that may not be needed.

Yes, my first thought was just to save the area tag as a string in mysql and that works and you can retrieve it, but I didn’t find a way to retrieve the associated area by a tag, though maybe my blonde butt missed it.

GetObjectByTag() ?

When I had tried using that it just … doesn’t seem to work. I suppose I’ll have to make sure its retrieving the tag properly. Hmm.

A thought: is there something I have to do other than run the SQL command to ensure it’s saved to the character file?

I use NWNX for this. That saves to the database not the character file. I think the in-box sql thingy will also save to the database file. So I don’t think there is anything else you need to do. In nwnx database you can look at it just like any other mysql DB so you can see what’s there. I believe there is a way to do that with the sqlite one too. Someone who has used the inbox sql might have a more complete answer…

You can also just SendMessageToPC or WriteTimestampedLogEntry what tag you pulled out to see of course.

GetObjectByTag() should work as long as the area with that tag still exists. Make sure the tags are unique across the module (totally, not just among areas … all tags).

The reason I ask that is looking at the BIC with Gffeditor I don’t see the fields despite the fact that I got no mysql error that I’m aware of, though that doesn’t mean I can’t’ve had one. Is there something to check for or otherwise trap errors in the Sql* functions? I was looking for a bad return value but as far as I can see it seems to returning success.

Something you have to keep in mind, not sure if it’s documented somewhere, but OnClientExit is too late to save stuff to the BIC file’s sqlite database.

For sql errors, you can look at the server log or make use of SqlGetError().

Something you have to keep in mind, not sure if it’s documented somewhere, but OnClientExit is too late to save stuff to the BIC file’s sqlite database.

Okay, this is probably exactly why then.
So in leiu of doing it then, how would I ensure that this location information is saved on exit?

See… I had assumed the sqlite db worked like the old nwn db (not specific to a particular character). That’s why we needed someone who knows about that specifically :slight_smile: That seems like it makes it less useful but maybe not or maybe you have a choice of where to put the data (like on a module wide sqlite db or something). But that’s getting off topic…

OnClientExit is too late to write things to the character file. You can do it periodically in a PC HB equivalent. You may end up with a small difference in actual location but it would also be relatively accurate if the game crashes.

At the risk of veering entirely off-topic here, I have to admit I’ve never really understood why server admins keep wanting to do this.

A character’s location is already persistent between logins. And there are non-trivial consequences for not resetting the starting position between server resets, particularly if the module has changed in the meantime.

For one, it means that characters can get stuck in inaccessible places forever. And it means that any changes to an area can make any previously stored position invalid or inaccessible. And, depending on the particulars of the server, there could be other undesirable consequences too (spawning in dangerous areas, etc.).

I’m not saying you shouldn’t do it (that depends on your design goals ultimately), but this just doesn’t seem like such an important feature to me. As a player, I’d rather be brought back to a “spawn point” somewhere the module builder knows is valid, accessible and sensible. My character’s last position could well be neither of these things.

No, it demonstrably is not, as if you log in, you will return to the Module Starting Point irrespective of where you were to begin with.

As to whether one should or should not do something, you’re free to make your own design decisions about your own modules, but I find a persistent world where the world doesn’t put you back where you were when you logged out quite jarring to say the least and that is the expectation of pretty much everyone whom plays on such a server.

What I do is save the player destination each time it enters an area transtition:

        SetCampaignString ("db_tdli", "RespawnAREA", sAreaTo, oPC);
        SetCampaignLocation ("db_tdli", "RespawnLOC", locPosTo, oPC);

and then retrieve it onClientEnter, build the location with the area tag, and make it jump

        string RespawnAREA = GetCampaignString ("db_tdli", "RespawnAREA", oPC);
        location RespawnLOC = GetCampaignLocation ("db_tdli", "RespawnLOC", oPC);
        vector RespawnPOS = GetPositionFromLocation (RespawnLOC);
        float RespawnFACE = GetFacingFromLocation (RespawnLOC);
        RespawnLOC = Location (GetObjectByTag (RespawnAREA),RespawnPOS,RespawnFACE);
        AssignCommand(oPC, ClearAllActions());

        if (GetObjectByTag (RespawnAREA) != OBJECT_INVALID) {
            AssignCommand(oPC, ActionJumpToLocation(RespawnLOC));
        }

You can even make a loop the player position gets saved in each loop, in my case I preferred the transtition basis… but probably gonna change it to a loop one.

1 Like

That seems a decent enough approach, I’ll give it a whirl!

Goes to show how much I know! I distinctively remembered this being persistent when hosting a local multiplayer game at some point, but it appears it isn’t in the dedicated server. That’s… weird, but then I get where this is coming from!

Never mind my musings on how to handle positions across server restarts then. It’s a completely different topic.

Yeah, I found it odd. If anything I’d want it the other way around preferrably - if I start a session with friends that isn’t loading from a save then yeah, I’d expect it to be at the module start position, but on a dedicated server I’d expect to hop back in where I left - or at least close to it, since it otherwise makes things a complete pain if you disconnect, for instance. But that’s neither here nor there.

I use this in my project, so after an update my test toon keeps persistence in single player.

What would be really ni e is some option to overwrite the Bic file when saving character in SP

Ah, there’s this checkbox – “Reload when empty” – which is checked by default when running the dedicated server. When I don’t check that, character location appears to be persistent between logins (since it’s still the same game running). Persistence across server restarts is a different matter.