RE: Sending a PC to a Stored Location After Server Reset - FAIL
#1
Posté 27 janvier 2013 - 11:13
I've got this weird issue with returning characters to their previous location when they reenter the server.
I store the character's location into the campaign database in the OnClientLeave event. Then in the OnClientEnter hook I check if the db has a stored location for that player and if it does I jump them to that location. Everything works fine as long as I don't restart the server.
When I restart the server the jump never occurs even though the location is still stored. I thought the player's public cd-key remained the same so I'm sure what the issue is...
I have done some digging and came up with an alternate - storing the location on a player database item. Works great as long as I do not restart the server. Do I need to export the character in the OnClientLeave event to get these variables to stick around after a server reset or is the problem with the stored location?
#2
Posté 27 janvier 2013 - 11:17
In NBDE Knat does just this when storing a location to the database.
#3
Posté 27 janvier 2013 - 11:17
#4
Posté 27 janvier 2013 - 11:26
The problem is that the game object for the area can change across restarts. And thus the Location data is not good after a restart.
The way around this is to come up with a better way to store the area. This will allow you to have the correct area when you recreate the location from its parts when you need it.
[edit] Thanks for posting this, BTW, it reminded me of this problem. I need to adjust my contribution t this month's CCC.
Modifié par henesua, 27 janvier 2013 - 11:30 .
#5
Posté 27 janvier 2013 - 11:29
void main()
{
object oPC = GetPCSpeaker();
object oArea = GetArea(oPC);
string sPCName = GetName(oPC); // Gets the name of the PC
string CDKey = GetPCPublicCDKey(oPC); // Gets the public CD Key of the player . . . adds to quality of check
string sID = GetStringLeft(sPCName,10); // Indivudual Character Used
string sHID = sID+CDKey; // HCR Style;
string sAreaName = GetName(oArea); // Sets up a string using the name of the Area
string sAreaTag = GetTag(oArea); // Sets up a string using the Tag of the Area
if(GetIsPC(oPC)||(GetIsDM(oPC) && !GetIsDMPossessed(oPC))) // Script will fire for PCs and DMs
{
vector vPosition = GetPositionFromLocation(GetLocation(oPC));
float nX = vPosition.x;
float nY = vPosition.y;
float nZ = vPosition.z;
int nAreaX = FloatToInt(nX);
int nAreaY = FloatToInt(nY);
int nAreaZ = FloatToInt(nZ);
string sAreaX = IntToString(nAreaX);
string sAreaY = IntToString(nAreaY);
string sAreaZ = IntToString(nAreaZ);
// Set an Int so we can check for a saved location in the portal or trigger
SetCampaignInt("PlayerStartLoc", "StartLocSet_" + sHID, 1, oPC);
// Create Persistent Location Data
SetCampaignInt("PlayerStartLoc", "AreaX_" + sHID, nAreaX, oPC);
SetCampaignInt("PlayerStartLoc", "AreaY_" + sHID, nAreaY, oPC);
SetCampaignInt("PlayerStartLoc", "AreaZ_" + sHID, nAreaZ, oPC);
SetCampaignString("PlayerStartLoc", "AreaTag_"+ sHID, sAreaTag, oPC);
// Tell the player what the Saved Area will be for verification
SendMessageToPC(oPC, "Persistent Saved Location is " + sAreaName);
// Apply a visual effect.
effect eVFX;
eVFX = EffectVisualEffect(VFX_FNF_STRIKE_HOLY);
ApplyEffectAtLocation(DURATION_TYPE_INSTANT, eVFX, GetLocation(oPC));
}
}
Modifié par Sadira of Tyr, 27 janvier 2013 - 11:32 .
#6
Posté 27 janvier 2013 - 11:46
#7
Posté 27 janvier 2013 - 11:59
// This script pulls data for location and jumps PC to last save point
// Use this in the onused event of a portal or onenter of a trigger or a conversation
void main()
{
// uncomment the proper definition of the player object for your use!!!
object oPC = GetEnteringObject();
//object oPC = GetLastUsedBy();
//ojbect oPC = GetLastSpeaker();
if(GetIsPC(oPC)||(GetIsDM(oPC) && !GetIsDMPossessed(oPC))) // Script will fire for PCs and DMs
{
string sPCName = GetName(oPC); // Gets the name of the PC
string CDKey = GetPCPublicCDKey(oPC); // Gets the public CD Key of the player . . . adds to quality of check
string sID = GetStringLeft(sPCName,10); // Indivudual Character Used
string sHID = sID+CDKey; // HCR Style user check
// Read Persistent Location Data
int nPlayerBeenHere = GetCampaignInt("PlayerStartLoc", "StartLocSet_" + sHID, oPC); // The check to see if PC has a saved location
int nAreaX = GetCampaignInt("PlayerStartLoc", "AreaX_" + sHID, oPC);
int nAreaY = GetCampaignInt("PlayerStartLoc", "AreaY_" + sHID, oPC);
int nAreaZ = GetCampaignInt("PlayerStartLoc", "AreaZ_" + sHID, oPC);
string sAreaName = GetCampaignString("PlayerStartLoc", "AreaName_" + sHID, oPC);
string sAreaTag = GetCampaignString("PlayerStartLoc", "AreaTag_"+ sHID, oPC);
// Set up the location from Database info
float y = IntToFloat(nAreaY);
float x = IntToFloat(nAreaX);
float z = IntToFloat(nAreaZ);
vector vTargetLoc = Vector(x, y, z);
location lTargetLoc = Location(GetArea(GetObjectByTag(sAreaTag)), vTargetLoc, 0.0);
if(nPlayerBeenHere == 1) // if the player has a saved location lets run this scripts
{
if (GetCurrentHitPoints(oPC)<=0) // See if the PC has 0 or less HPs . . . added this for HCR death system
{
SendMessageToPC(oPC,"You are still be dead...");
}
else // If the PC is above 0 HPs, send them to their last save location
{
SendMessageToPC(oPC,"Portaling to your Saved Location in 3 Seconds...");
DelayCommand(3.0, AssignCommand(oPC, ActionJumpToLocation(lTargetLoc)));
}
}
}
}
#8
Posté 28 janvier 2013 - 12:09
I see no need to break the entire location down for storage. The only problem with the stored location is the area, and that is only if the module was worked on and the area order changes.
Simply storing the location and the area tag should be good enough to rebuild a valid location.
location lLoc = Get**Location();
string sArea = Get**AreaTag();
lLoc = location (GetObjectByTag(sArea), GetpositionFromLocation(lLoc), GetFacingFromLocation(lLoc));
May be errors above, Just typing from memory to give an Idea.
As far as the problem you are having, I would have to check and see if the location in the OnClientLeave event is valid. You may need to store the location before that event fires. After all does not the Area Exit Event fire first? Once the pC leaves the area there location is no longer valid.
Modifié par Lightfoot8, 28 janvier 2013 - 12:11 .
#9
Posté 28 janvier 2013 - 12:48
Tried moving the store location script to Area OnExit and still no go. It appears that nothing is being stored in the database for the area, making me certain that the area or location is no long valid even from that event.
Modifié par Pstemarie, 28 janvier 2013 - 01:30 .
#10
Posté 28 janvier 2013 - 01:29
location GetSpellFocusLocation(object oFocus)
{
return Location( GetObjectByTag(GetLocalString(oFocus, SPELLFOCUS_LOCATION_TAG)),
Vector( GetLocalFloat(oFocus, SPELLFOCUS_LOCATION_X),
GetLocalFloat(oFocus, SPELLFOCUS_LOCATION_Y),
GetLocalFloat(oFocus, SPELLFOCUS_LOCATION_Z)
),
GetLocalFloat(oFocus, SPELLFOCUS_LOCATION_F)
);
}
// Stores a location on a spell focus. - [FILE: spellfocus_inc]
void StoreSpellFocusLocation(object oFocus, location lLoc)
{
vector vPos = GetPositionFromLocation(lLoc);
SetLocalString(oFocus, SPELLFOCUS_LOCATION_TAG, GetTag(GetAreaFromLocation(lLoc)));
SetLocalFloat(oFocus, SPELLFOCUS_LOCATION_X, vPos.x);
SetLocalFloat(oFocus, SPELLFOCUS_LOCATION_Y, vPos.y);
SetLocalFloat(oFocus, SPELLFOCUS_LOCATION_Z, vPos.z);
SetLocalFloat(oFocus, SPELLFOCUS_LOCATION_F, GetFacingFromLocation(lLoc));
}
#11
Posté 28 janvier 2013 - 01:53
1. The PW is a LAN PW and although I could leave my computer on all the time I really don't want to pay the higher electricity bill to do so - besides we only play once every other week or so.
2. The Server must be able to be reset (see above)
3. Therefore, I want to be able to store a PCs location when they leave the module and I want this to be persistent across resets.
4. I'd like to avoid using a trigger or conversation to do so. I just want the player to be able to exit and when they do the game stores their location in the database.
5. I'm using bioware's database because NWNX is so far over my head I feel like Lurch whenever I look at it.
#12
Posté 28 janvier 2013 - 02:09
Pstemarie wrote...
I want to be able to store a PCs location when they leave the module and I want this to be persistent across resets.
I store this on module heartbeat and it works for me. Module Heartbeat typically runs between 4 and 6 times a minute as far as I can tell. I'll post my code on pastebin.
Pstemarie wrote...
I'm using bioware's database because NWNX is so far over my head I feel like Lurch whenever I look at it.
Bio DB is adequate. But I recommend using Knat's NBDE to increase its speed. I fixed a few functions in it which you should have access to now.
Modifié par henesua, 28 janvier 2013 - 04:31 .
#13
Posté 28 janvier 2013 - 02:15
#14
Posté 28 janvier 2013 - 02:17
Otherwise, I can write a non-NBDE system for this if you would like. In fact... the one I posted above could easily be adapted.
#15
Posté 28 janvier 2013 - 02:29
#16
Posté 28 janvier 2013 - 04:40
Using the heartbeat script to store the location to the BioWare database is a pretty decent idea. Then, when your player(s) log back in, the location is reconstructed during the player client enter script run.
I just whipped up a quick and dirty set of script blocks that should help you out. Just copy/paste into your own scripts.
persistentlocation.txt
#17
Posté 28 janvier 2013 - 04:53
#18
Posté 29 janvier 2013 - 12:17
I did also relearn something - why I dumped NBDE originally. When I converted the write functions over to NBDE everything broke. For some reason the database was no longer being written too. I tried deleting the database and starting over, but to no avail. I'm thinking it has something to do with the subsystems I've included:
The Krit's Alternate Horse Scripts
Axe Murderer's Killer Death System
Scarface's Persistent Banking System
Screw Tape's Simple XP
I have no idea what's causing the conflict because everything compiles fine once NBDE is added. NBDE just won't write to the database or create it if/when needed.
#19
Posté 29 janvier 2013 - 12:31
Glad the scripting will work with your module's systems.
I too got rid of NBDE. It worked well for quite a while, but then started losing data on a too-often basis (like journal entries and quest states I was storing). Probably because I was using it to store a lot of variables. I ended up switching to a small PC inventory item for persistent data storage for almost everything (PC skins are frequently replaced in my PW, so that isn't a viable storage item).
Modifié par The Amethyst Dragon, 29 janvier 2013 - 12:32 .
#20
Posté 29 janvier 2013 - 12:48
I still have reservations about using a Heartbeat like this, but I'm sure the quantity of data won't be too taxing. If I notice too much lag I'll just store the values on the PC Data Item instead.
EDIT - Just thought of a way I can reduce any drag that might be caused by this...I can skip the location storage if the PC is in combat.
Modifié par Pstemarie, 29 janvier 2013 - 01:00 .
#21
Posté 29 janvier 2013 - 02:19
#22
Posté 29 janvier 2013 - 03:02
object oPlayer = OBJECT_SELF;
object oDBItem = GetItemPossessedBy(oPlayer, "item tag");
location lPlayer = GetLocation(oPlayer);
string sAreaTag = GetTag(GetArea(oPlayer));
Store Location:
SetLocalLocation(oDBItem ,"MY_LOC" ,lPlayer);
SetLocalString(oDBItem ,"MY_AREA" ,sAreaTag);
Rebuild Location:
location lLoc = GetLocalLocation(oDBItem ,"MY_LOC");
string sAreaTag = GetLocalString(oDBItem ,"MY_AREA");
lLoc = Location(GetObjectByTag(sAreaTag),
GetPositionFromLocation(lLoc),
GetFacingFromLocation(lLoc));
There's no need to store all the separate x,y,z and what not. I also dont use HB to store. Just multiple other events. OnPlayerRest, area OnEnter/OnExit, etc..
Glad to hear you got it worked out.
Modifié par GhostOfGod, 29 janvier 2013 - 03:05 .
#23
Posté 29 janvier 2013 - 03:07
Of course. Because the only bad part of the data is the area so you can still use everything else.
I've got to edit some scripts.
Thanks.
#24
Posté 29 janvier 2013 - 10:00
EDIT - Everythings working smoothly now....
I had to add some checks to the function KDS1OnClientEnter() to check if an entering PC had the PC Data Item and if so port them to their stored persistent location. If they don't have the PC Data Item then they are assumed to be a First Time Login and sent to the Character Setup area.
Next, I had to relocate the module's start location to the module's first area - where they go when they exit the Character Setup area. KDS1OnClientEnter() was then moved from the module's OnClientEnter script to the OnEnter script for this area.
So now the module basically functions as so:
PC logs into server and is sent to the module's first area. The area's OnEnter event then runs them through the KDS1OnClientEnter() function and checks for:
- If the character went to the Purgatory area then logged out to avoid the penalty, they are penalized and sent to the Church area - where all characters go when leaving Purgatory.
- Else, If the character was a "dead" body when they logged out they are sent to Purgatory.
- Else, if none of the above applies and the character is not a first time login, then they are sent to their stored location.
- Else, if a first time login they are sent to the Character Setup area.
Modifié par Pstemarie, 29 janvier 2013 - 11:44 .
#25
Posté 29 janvier 2013 - 10:06
I've got persistence working now for remaining feat (thanks to HCR 2.0) and spell uses. I've also modified the rest event so that feats and spells can only be regained once every 24 hours. Furthermore, for every 8 hour cycle you rest, you regain 1 HP per Level.





Retour en haut







