Author Topic: OnClientLeave  (Read 498 times)

Legacy_DM Vandel

  • Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
OnClientLeave
« on: March 01, 2011, 08:25:25 pm »


               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
               
               

               
            

Legacy_Baragg

  • Sr. Member
  • ****
  • Posts: 496
  • Karma: +0/-0
OnClientLeave
« Reply #1 on: March 01, 2011, 08:28:32 pm »


               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.
               
               

               
            

Legacy_DM Vandel

  • Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
OnClientLeave
« Reply #2 on: March 01, 2011, 08:43:47 pm »


               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?
               
               

               
            

Legacy_Baragg

  • Sr. Member
  • ****
  • Posts: 496
  • Karma: +0/-0
OnClientLeave
« Reply #3 on: March 01, 2011, 09:40:56 pm »


               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.
               
               

               
            

Legacy_Baragg

  • Sr. Member
  • ****
  • Posts: 496
  • Karma: +0/-0
OnClientLeave
« Reply #4 on: March 01, 2011, 09:47:43 pm »


               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]
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
OnClientLeave
« Reply #5 on: March 01, 2011, 09:53:29 pm »


               
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?
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
               
               

               
            

Legacy_DM Vandel

  • Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
OnClientLeave
« Reply #6 on: March 01, 2011, 10:22:37 pm »


               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 .
                     
                  


            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
OnClientLeave
« Reply #7 on: March 01, 2011, 10:46:45 pm »


               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...
               
               

               
            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
OnClientLeave
« Reply #8 on: March 02, 2011, 01:21:33 pm »


               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.
               
               

               
            

Legacy__Knightmare_

  • Full Member
  • ***
  • Posts: 191
  • Karma: +0/-0
OnClientLeave
« Reply #9 on: March 02, 2011, 01:43:28 pm »


               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.
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
OnClientLeave
« Reply #10 on: March 02, 2011, 02:36:49 pm »


               

_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 '<img'>) and isnt better than OnEnter script
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
OnClientLeave
« Reply #11 on: March 02, 2011, 02:44:15 pm »


               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 .
                     
                  


            

Baaleos

  • Administrator
  • Hero Member
  • *****
  • Posts: 1916
  • Karma: +0/-0
OnClientLeave
« Reply #12 on: March 02, 2011, 03:27:23 pm »


               

_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)
               
               

               
            

Legacy_Shadooow

  • Hero Member
  • *****
  • Posts: 7698
  • Karma: +0/-0
OnClientLeave
« Reply #13 on: March 02, 2011, 03:34:11 pm »


               

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.
               
               

               
            

Legacy_DM Vandel

  • Newbie
  • *
  • Posts: 8
  • Karma: +0/-0
OnClientLeave
« Reply #14 on: March 03, 2011, 08:50:03 pm »


               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