Aller au contenu

Photo

OnClientLeave


  • Veuillez vous connecter pour répondre
22 réponses à ce sujet

#1
DM Vandel

DM Vandel
  • Members
  • 4 messages
My clean up script for an area works correctly when someone leaves the area. But if the person logs off, it does not seem to trigger the onExit event for the area.

When the person logs back in (if the server has not rebooted yet) the player is in the same spot when he logged out.

By using the module onClientLeave script how do I move the player to the starting location of the module?

I ask because death scripts you have a limited time due to the creature no longer existing, is logging out the same?

My current OnClientLeave script is
void main()
{
    SavePCInfo(GetExitingObject());
}

Will adding a line JumpToObject and the objet being a waypoint work?

I know I can test it my self but because I can only test it on the live server I want to be sure prior to putting it there.

Thanks in advance

#2
Baragg

Baragg
  • Members
  • 271 messages
You would use the OnClientEnter to move the PC to the start area. Have a waypoint in the start area, and on client enter check the tag of the area they are in, if it is not the tag of the start area move them to the waypoint in the start area.

#3
DM Vandel

DM Vandel
  • Members
  • 4 messages
Baragg,

Thanks for your quick reply. That would work to get the player back to the start of the module, but how do I get the areas clean up script to fire when logging out?

here is the start of the area clean up script:

void main()
{
if ((!GetIsAreaOccupied(OBJECT_SELF)) && (GetIsPC(GetExitingObject())))
{
It looks like the PC does not actually exit the area when logging out. Like a dead creature you have to scan for the bodybag, not the creature. What is being left behind when logging out? Or am I over thinking this?

#4
Baragg

Baragg
  • Members
  • 271 messages
Mayhap have your OnClientExit get the area the pc was in, and run your clean up on that if there are no other pcs in that area? Post your OnClientExit script.

#5
Baragg

Baragg
  • Members
  • 271 messages
Here I had this PC check in my scraps folder, not sure who wrote it but mayhap it shall do the trick:

[nwscript]
// * returns true if there is no player in the area
// * has to be ran from an object
// *forgot to mark who wrote this but it wasn't me Baragg
int NoPlayerInArea()
{
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
if (GetIsObjectValid(oPC) == TRUE)
return FALSE;
return TRUE; // * no player in area
}

void main()
{

if(NoPlayerInArea() == TRUE)
{
//do clean up stuff here
}
SavePCInfo(GetExitingObject());
}[/nwscript]

#6
Shadooow

Shadooow
  • Members
  • 4 470 messages
[quote]Baragg wrote...

Mayhap have your OnClientExit get the area the pc was in, and run your
clean up on that if there are no other pcs in that area?[/quote]except PC location in OnClientLeave is not valid anymore

[nwscript]
// * returns true if there is no player in the area
// * has to be ran from an object
// *forgot to mark who wrote this but it wasn't me Baragg
int NoPlayerInArea()
{
object oPC = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC);
if (GetIsObjectValid(oPC) == TRUE)
return FALSE;
return TRUE; // * no player in area
}

void main()
{

if(NoPlayerInArea() == TRUE)
{
//do clean up stuff here
}
SavePCInfo(GetExitingObject());
}[/nwscript][/quote]old and incorrect, you must use both alive and dead parameters for this function

the problem the OP has seems to happen only when the person logging off is dead, therefore this will fix it:

1 - when player die, set his current area as local object with varname for example "LAST_AREA"
2 - in OnClientLeave if valid object on PC with varname "LAST_AREA" then run a clean script on this area (with re-checking any other players inside!)
3 - in OnClientEnter, delete "LAST_AREA" local var

#7
DM Vandel

DM Vandel
  • Members
  • 4 messages
Thanks both of you for answering. I was using the bodybag as an example as to, cant query the creature anymore. If a person logs out, can you still query the person or do you need to query something else? I have one player in particular that stays in one area, killing monsters going in a circle around the area, keep doing this not picking up the drops, some plot items some not. over and over, eventually logs off (lunch, take a break I don't know). logs back in and does it some more.

The person in question has been asked to clean up after him self but has some handicaps and can't see/listen well and I think NWN is his only source of entertainment. I don't want to discourage the guy from playing or get him upset. I can't write a script just for that one area because I noticed as he gains levels he moves to another area and does the same thing.

The area on exit script does not fire when a player logs out so I'm looking at the onclientleave

Here is what I came up with:
void main()
{
object oPC = GetExitingObject();
object oTarget = GetWaypointByTag("t_po_savecheat");
AssignCommand(oPC,ActionJumpToObject(oTarget));
SavePCInfo(oPC);
}
the "SavePCInfo" is in an include which I need to take a look at because the include is used in the OnClientEnter script. But that still does not explain why the area onexit script does not fire.
By puting the action jumptoobject in the onclientexit (jumping to the area limbo) would this triger the area's onexit script? or is the PC already gone persay?

Modifié par DM Vandel, 01 mars 2011 - 10:45 .


#8
Shadooow

Shadooow
  • Members
  • 4 470 messages
This does not work as I said.

In the time when OnClienLeave fires the player is long time gone. You can only GetLocal stuff from him and possible get current/max hitpoints.

Area onexit does not fire due to bug, but I was pretty sure it happens only when player is dead. However it doesn't seems that this player loggs off dead. If he would logged off dead, it would be easy, but if he logs out healthy and the area OnExit still don't fire the remaining options are very rough.

Basically you would have to set OnEnter script into all areas where you would save the area object on PC.

save last area for scripting purposes from OnEnter

void main()
{
object oPC = GetEnteringObject();
SetLocalObject(oPC,"LAST_AREA",OBJECT_SELF);
}


then you would be able to retrieve last area he were before logged off and make any neccesary actions in it...

#9
Baaleos

Baaleos
  • Members
  • 1 330 messages
NWNX Might be able to fix the Bug you described above.

NWNX Could, in theory hook onto the Function that fires when a player leaves the module, and because the Hook runs before the function runs, the Player Object might exist at that point in time, allowing the script to get hold of the object that left the server, and the area they are in.

Basically, you would be hooking onto the function that fires, before the player actually gets disconnected.

Note - the Player Object exists on Server and Client side,
When the Client disconnects, or attempts to disconnect, a message is sent to the server, which then tells the server that a player is leaving, the server then uses this message to trigger a removal of the player/character from the area etc and the module.

So technically, after you do disconnect, a few functions do run in the internal memory, where your Player Does exist still, one of those functions would be incharge of removing your character from the server

I will have a look when I get home, in IDA, to see where the function is in memory.
It could be a case of overriding the onClientLeave script, with a nwnx events script.

#10
_Knightmare_

_Knightmare_
  • Members
  • 643 messages
Maybe run it off the area heartbeat. Have it set a variable on area when a PC enters area, check for variable on heartbeat, if none, run clean up script. Heartbeat scripts run on an area even if there is no PC located there. Might be too taxing on the system though. Maybe have it set an "Area_Cleaned" variable right after the clean-up script finishes. If either Pc is in area, or area has already been cleaned, end script. Just a thought.

#11
Shadooow

Shadooow
  • Members
  • 4 470 messages

_Knightmare_ wrote...

Maybe run it off the area heartbeat. Have it set a variable on area when a PC enters area, check for variable on heartbeat, if none, run clean up script. Heartbeat scripts run on an area even if there is no PC located there. Might be too taxing on the system though. Maybe have it set an "Area_Cleaned" variable right after the clean-up script finishes. If either Pc is in area, or area has already been cleaned, end script. Just a thought.

That has the same downside as OnEnter script in area -> you must set a script into all areas (manually or via letoscript-moneo, so manually :D) and isnt better than OnEnter script

#12
Shadooow

Shadooow
  • Members
  • 4 470 messages
Pre-maded solution:

OnEnter on every area or at least in those you want to clean up

void main()
{
object oPC = GetEnteringObject();
SetLocalObject(oPC,"LAST_AREA",OBJECT_SELF);
}


OnClientLeave

void main()
{
object oPC = GetExitingObject();
object oLastArea = GetLocalObject(oPC,"LAST_AREA");
 if(oLastArea != OBJECT_INVALID)
 {
  object oPlayer = GetFirstPC();
  while(oPlayer != OBJECT_INVALID)
  {
   if(GetArea(oPlayer) == oLastArea)
   {
   return;//there are still players in the area the pc just exited
   }
  oPlayer = GetNextPC();
  }
 #####your function or execute your script that clean the oLastArea####
 }

}

OnClientEnter //this can be ommited, but its better to add this line into your existing OnClientEnter

void main()
{
object oPC = GetEnteringObject();
SetLocalObject(oPC,"LAST_AREA",OBJECT_INVALID);
}


Modifié par ShaDoOoW, 02 mars 2011 - 02:44 .


#13
Baaleos

Baaleos
  • Members
  • 1 330 messages

_Knightmare_ wrote...

Maybe run it off the area heartbeat. Have it set a variable on area when a PC enters area, check for variable on heartbeat, if none, run clean up script. Heartbeat scripts run on an area even if there is no PC located there. Might be too taxing on the system though. Maybe have it set an "Area_Cleaned" variable right after the clean-up script finishes. If either Pc is in area, or area has already been cleaned, end script. Just a thought.



Running a onServerHeartBeat would work as well.

Run Script
Loop through players,
Store a LocalObject relating to the player (the object being the area they are in) - Store this on the server

Loop through each of those locally stored objects, and if the player that the area is stored, in relation to, is not in the server, then we can assume that the area has been left, via onClientLeave.

eg
I enter an area
Heartbeat script finds me
Stores the area I am in, on the server as   Baaleos_area   (the value being the area object)

OnClientLeave function should be able to get your PCPlayerName, which would be enough to make this work.

Just Use the PCPlayerName to get the <PlayerName>_area  object that was stored on the server, and then fire the cleanup script on that area.


Note - It might be better to make a Pseudo HB for this, instead of a Server HB,
You can Control the Rate of Fire etc, and overhead more accurately with Pseudo's.

If it were me, I would integrate nwnx_system with it, and have the Rate of Fire decrease as the cpu usage increases, and increase the rate of fire, if there is lots of cpu power to spare.

Other factors to think of are
1. Number of players.  If we are talking about 4 players, then you could have this script firing every 1 second without much degradation. If however talking about 60 players, then you might want to increase the delay between beats to about 6 seconds. (More players, means more lines of code being executed, and nwserver being single threaded, a Longer Script will cause freezes and lock ups if they are not handled safely)

#14
Shadooow

Shadooow
  • Members
  • 4 470 messages

Baaleos wrote...

OnClientLeave function should be able to get your PCPlayerName, which would be enough to make this work.

No is not unless you set this information in OnClientEnter into variable on PC.

#15
DM Vandel

DM Vandel
  • Members
  • 4 messages
Thanks everyone for the help. I do not want to use the heartbeat idea because the reason for the clean up script is to reduce lag.

NWNX I've looked at in the past for other features but decided against using it because there are already to things being stored in a database and afraid I will loose that data in the transition.

That leaves ShaDoOoW's method. I think I'm pushing 400 areas, it would just be too time consuming to fix something for just one player.

Thanks again for your help

#16
Shadooow

Shadooow
  • Members
  • 4 470 messages
Well there is automatical method how to set script into every area in your module, see my Door System at vault, there is a special letoscript distribution (Moneo by dragonsong) and letoscript script which adds scripts into all doors in your module, it should be easy to adjust it to set area's scripts, and if you would have problem with it I can help you. Or you can put it only in the areas visited by this specific player. It doesn't have to be in all of them in order to work.

#17
Baaleos

Baaleos
  • Members
  • 1 330 messages
Note
ShaDoOw asked me to have a look in IDA for a way to hook on the ClientLeave event, in order to be able to get the player/character object in a nwnscript before they leave the server.


I had success and found a memory location for 'RemovePlayerFromWorld'.
I passed the memory addresses over to Maxrock, and hes added functionality into nwnx_funcs allowing you to use a new event hook.

Allows you to get the Character, the area, and even items in his inventory as he is leaving the server.
And use them in nwnscript.

#18
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
Question: Have you tested the function for when the client crashes,

#19
Baaleos

Baaleos
  • Members
  • 1 330 messages
Short answer = No - I havent had a chance to test it at all yet.

But, in terms of when a Client Crashes, it would be indistinguishable from a Normal Client Disconnect from the point of view of the server. They both call the same function on the server.

The RemovePlayerFromWorld function would still be run, as it is kicked off by the ChangePlayerCount function.

eg - If the ChangePlayerCount function runs, then its going to run the RemovePlayerFromWorld function. (this is the function that makes the player character vanish from the world)

#20
Lightfoot8

Lightfoot8
  • Members
  • 2 535 messages
True, Unless the server is sending a request for the Player Public CD key  and the client is no longer there. Also inventory would be a problem If the Server is running a local vault. The Client is just no longer there is save the Data to.

Modifié par Lightfoot8, 10 mars 2011 - 05:15 .


#21
Shadooow

Shadooow
  • Members
  • 4 470 messages
Hmm how can server run these internal functions if it crashed? I don't think that, in this case anything is run...

#22
Baaleos

Baaleos
  • Members
  • 1 330 messages
If the server crashes - yes, nothing will run.
If the Client crashes - the server still retains an object of the player/character. It is the RemovePlayerFromWorld function that would remove them from existance anyway, and we are running the onClientLeave hook before this function.

Techically, and in theory, th function would be run, before the character is destroyed, even if there isnt a player around to control him.
But we are talking about a time frame of miliseconds etc,
Long enough for a script to run, before the hook ends, and carries on running the onClientLeave code.

#23
Shadooow

Shadooow
  • Members
  • 4 470 messages
ah, my bad i missed the word "client", ok so I proofed it with the MaxRock nwnx_funcs' hook and it does fire reliably and with all informations available also in case of client crash

Modifié par ShaDoOoW, 11 mars 2011 - 07:32 .