PDA

View Full Version : Zone Reset Quest on a Timer


trevius
02-26-2008, 10:41 AM
First of all, I want to give credit and thanks to So_1337 and Derision for helping me get this quest working.

The primary idea behind this script is that it can be used to reset zones to clear out player ghosts. A player ghost is what happens sometimes when players use /exit or /quit or crash, and sometimes even when they /log. The character stays in the game until the server or zone is reset, or until they are #kicked by a GM. The easy way to tell if a character is a ghost is to inspect them. If the inspect window doesn't pop up and you have /toggleinspect on, then that character is a ghost.

I don't know if ghosting is an issue on Linux servers, but all windows servers I know of have the ghosting issue. Overtime, the ghosts and connections build up and can cause incredible lag. This means that most decently populated windows server need to be rebooted every day or they become unplayable.

In this thread, I will include the actual script I am running in Nexus right now that is working, and also a test script with shorter reset times on it so people can try it out. At the end of the 2 posts, I will give details about setting it up and other information I have. I will also reply to these posts later when I have had more testing and feedback from my players, and will report if it helped server performance noticeably or not.

Here is the working script I am running in nexus right now to reset the zone every 4 hours if there are players in it:

#############
#Quest Name: 4 Hour Zone Reset Script
#Author: Trevius
#NPC's Involved: Storm Haven
#Items Involved: None
#############
###NPC 1
#Name: Storm Haven (Or whatever your server name Is)
#Race 127 (invisible man), Texture of 0, Size 1, gender of 0, body type 11
#Location: 0,0,-999 of the Nexus
#level: 100
#Type: Quest NPC that resets the zone
#Loot: N/A
#############

sub EVENT_SPAWN {
quest::settimer("reset",14400);
quest::settimer("warning1",12600);
quest::settimer("warning2",13200);
quest::settimer("warning3",13800);
quest::settimer("warning4",14100);
quest::settimer("warning5",14280);
quest::settimer("warning6",14340);

$counter = 0;
}


sub EVENT_TIMER{
if ($timer eq "warning1"){
quest::stoptimer("warning1");
quest::shout("NEXUS will be restarting in 30 minutes. Please zone out before that time.");}

if ($timer eq "warning2"){
quest::stoptimer("warning2");
quest::shout("NEXUS will be restarting in 20 minutes. Please zone out before that time.");}

if ($timer eq "warning3"){
quest::stoptimer("warning3");
quest::shout("NEXUS will be restarting in 10 minutes. Please zone out before that time.");}

if ($timer eq "warning4"){
quest::stoptimer("warning4");
quest::shout2("NEXUS will be restarting in 5 minutes. Please zone out before that time.");}

if ($timer eq "warning5"){
quest::stoptimer("warning5");
quest::shout("NEXUS will be restarting in 2 minutes. Please zone out before that time.");}

if ($timer eq "warning6"){
quest::stoptimer("warning6");
quest::shout2("NEXUS will be restarting in 1 minute! Please zone out NOW!");}

if ($timer eq "reset"){
quest::stoptimer("reset");
quest::shout2("Nexus is being restarted right now! It will be back immediately, so you can log back in right away.");
kill SEGV => $$;}
}

trevius
02-26-2008, 11:01 AM
And here is a script that will reset the zone after 2 minutes, so anyone can test it out quickly and verify that it is working properly before putting on the actual 4 hour script:

#2 Minute Zone Reset For Testing

my $counter;

sub EVENT_SPAWN {
quest::settimer("reset",121);
quest::settimer("warning1",1);
quest::settimer("warning2",61);
quest::settimer("warning3",91);
quest::settimer("warning4",111);
quest::settimer("warning5",116);
quest::settimer("warning6",120);

$counter = 0;
}

sub EVENT_TIMER{
if ($timer eq "warning1"){
quest::stoptimer("warning1");
quest::shout("NEXUS will be restarting in 2 minutes. Please zone out before that time.");}

if ($timer eq "warning2"){
quest::stoptimer("warning2");
quest::shout2("NEXUS will be restarting in 1 minute. Please zone out before that time.");}

if ($timer eq "warning3"){
quest::stoptimer("warning3");
quest::shout("NEXUS will be restarting in 30 seconds. Please zone out before that time.");}

if ($timer eq "warning4"){
quest::stoptimer("warning4");
quest::shout("NEXUS will be restarting in 10 seconds. Please zone out before that time.");}

if ($timer eq "warning5"){
quest::stoptimer("warning5");
quest::shout("NEXUS will be restarting in 5 seconds. Please zone out before that time.");}

if ($timer eq "warning6"){
quest::stoptimer("warning6");
quest::shout("NEXUS will be restarting in 1 seconds. Please zone out NOW!");}

if ($timer eq "reset"){
quest::stoptimer("reset");
quest::shout2("Nexus is being restarted right now! It will be back immediately, so you can zone back in right away.");
kill SEGV => $$;
}
}

To disable the zone kill, all you have to do is comment out the line at the bottom like this: "#kill SEGV => $$;" and then do a #reloadquest when you log in. I think 2 minutes should be plenty of time to get back in and reload quests between the 2 minute resets. You should be able to see the shouts in this script from other zones as well, since some of them use "shout2" which is server-wide shout. So, you can zone to another zone and wait for the shout message to come across and then zone back in right away. But, remember that there has to be someone in the zone if you are using dynamic zones, otherwise the zone will unload before the reset happens. It resets 2 minutes after the NPC spawns, which happens when someone loads into the zone.

You can test this script on any NPC you want, but you will probably want to make a spawn named "<Your Server Name Here>" or "Zone Resetter" and then make it race 127 for invisible man and body type 11 for untargetable.

Once you create the first NPC, you can use GeorgeS' Spawn Editor and load up Nexus spawns. Then, find the Spawn you created and use "add line" in the spawn section on the right. You can add a line for each zone you want to run the script in and simply put the zone name there, and it will spawn in each of your zones without having to go to each zone spawn table and adding it 1 by 1. Next, all I did was set the spawn locs in all zones to 0, 0, -999 so that it will spawn under the world so no one can see it. It may still show up on track, but that isn't a big deal.

Last, you go zone by zone and add the quest to that NPC for each zone. The only thing that has to change for each zone is the zone name in the shouts. You can also change the reset and warning timers (just use a calculator to get the numbers). I have Nexus and all low level zones set to 4 hour resets. All mid to high level exp zones set to 6 hour resets. And all raid zones are set to 8 hour resets with 2 hours of warnings (instead of 30 mins) so players can plan accordingly.

So far the scripts seem to be working on my server. I just added them in last night, so I am waiting to hear feedback from my players to see if they are working right and if they are helping server performance. Feel free to test them out now if you like. I will report back later when I gather more information from my players and do more testing. At this time, I think this is probably the best (and only) work-around for player ghosting. If it works as I think it should, it should make a huge impact on server performance. It should also mean less intervention from admins to reset the server and zones so often. Might be good if you had to go away for the weekend or something :D

One more thing that I should mention is that the script isn't exactly doing a reset on the zone. It also isn't exactly crashing the zone. I don't even know exactly what the command "kill SEGV => $$;" does (Derision provided it to me as a solution), but it seems to just stop the zone process. You will get the windows explorer window pop-up like on a normal zone crash, but you don't get the crash error messages. From my testing in Nexus, I would see the zone stop and then it would load up another zone server and restart nexus when a player loaded into it.

Let me know if you guys have any questions or feedback on this quest. You can reply here or PM me on my forums, or whatever.

trevius
02-26-2008, 10:09 PM
After 1 day of running this so far, my players now report that they haven't seen a single bit of server-side lag all day :D I will try running the server for a few days straight soon and see how that goes.

The first bug I have found so far is that one of my quest NPCs in PoTimeB was shouting that Crushbone was going to reset and it reset PoTimeB instead. The zone resetting NPC in potimeb is definitely only set to reset potimeb and only set to warn that it is shutting down that zone. Crushbone has a completely different quest with it's own spawn that shouts about Crushbone being reset.

When I first put the quests in, I had all of the timers set to the same names in each zone and I think this may have been the problem. All of the timers were $reset, $warning1, $warning2, etc. Now, I have renamed each of them in the quests for each zone. For example, Crushbone timers are now called $cb_reset, $cb_warning1, $cb_warning2, etc. I will test and see if that clears up my problem.

The only other thing I suspect that might be the cause is that I used 1 NPC type for all zones. I used GeorgeS' tool to setup 1 spawn that spawns in all of my custom zones. You just add a line under "Spawn2 Spawn Locations" section and set which zone you want it to spawn in. I added 1 line per custom zone I have and them all set to spawn from the same "Spawn Entries" NPC. If the change to my timer names doesn't fix the problem, I will just make individual spawn entries for each custom zone instead of 1 for all.

AndMetal
02-26-2008, 10:38 PM
The first bug I have found so far is that one of my quest NPCs in PoTimeB was shouting that Crushbone was going to reset and it reset PoTimeB instead. The zone resetting NPC in potimeb is definitely only set to reset potimeb and only set to warn that it is shutting down that zone. Crushbone has a completely different quest with it's own spawn that shouts about Crushbone being reset.

You could always make just 1 quest, in say the plugins folder, and use the variable $zoneln to make the quest dynamically say the zone's long name:


#############
#Quest Name: 4 Hour Zone Reset Script
#Author: Trevius
#NPC's Involved: Storm Haven
#Items Involved: None
#############
###NPC 1
#Name: Storm Haven (Or whatever your server name Is)
#Race 127 (invisible man), Texture of 0, Size 1, gender of 0, body type 11
#Location: 0,0,-999 of the Nexus
#level: 100
#Type: Quest NPC that resets the zone
#Loot: N/A
#############

sub EVENT_SPAWN {
quest::settimer("reset",14400);
quest::settimer("warning1",12600);
quest::settimer("warning2",13200);
quest::settimer("warning3",13800);
quest::settimer("warning4",14100);
quest::settimer("warning5",14280);
quest::settimer("warning6",14340);

}


sub EVENT_TIMER{
if ($timer eq "warning1"){
quest::stoptimer("warning1");
quest::shout("$zoneln will be restarting in 30 minutes. Please zone out before that time.");}

if ($timer eq "warning2"){
quest::stoptimer("warning2");
quest::shout("$zoneln will be restarting in 20 minutes. Please zone out before that time.");}

if ($timer eq "warning3"){
quest::stoptimer("warning3");
quest::shout("$zoneln will be restarting in 10 minutes. Please zone out before that time.");}

if ($timer eq "warning4"){
quest::stoptimer("warning4");
quest::shout2("$zoneln will be restarting in 5 minutes. Please zone out before that time.");}

if ($timer eq "warning5"){
quest::stoptimer("warning5");
quest::shout("$zoneln will be restarting in 2 minutes. Please zone out before that time.");}

if ($timer eq "warning6"){
quest::stoptimer("warning6");
quest::shout2("$zoneln will be restarting in 1 minute! Please zone out NOW!");}

if ($timer eq "reset"){
quest::stoptimer("reset");
quest::shout2("$zoneln is being restarted right now! It will be back immediately, so you can log back in right away.");
kill SEGV => $$;}
}


Should save a ton of headache if you want to make each zone the same. And if you don't, you should be able to create the individual quests for the specific zones, while still keeping the main one in plugins.

You may also notice I removed "$counter = 0;" because it doesn't seem to do anything in the script.

When I first put the quests in, I had all of the timers set to the same names in each zone and I think this may have been the problem. All of the timers were $reset, $warning1, $warning2, etc. Now, I have renamed each of them in the quests for each zone. For example, Crushbone timers are now called $cb_reset, $cb_warning1, $cb_warning2, etc. I will test and see if that clears up my problem.

If I'm not mistaken, if you define the variables at the beginning of the script (before the subs) using my (http://perldoc.perl.org/functions/my.html) (so my $reset, my $warning1, etc), I believe it will give you the desired result without having to create a script for each zone.

trevius
02-27-2008, 10:02 AM
Thanks, that is all useful information.

I didn't know what "$counter = 0;" did either, but I normally write my scripts by example and the one I used that had timers had that in there and I couldn't figure out why, so I just stuck it in mine lol. You are probably right, it most likely doesn't need to be there.

As for using $zoneln instead of manually editing, that should work well too. I did mine manually, because I wanted them to all be in CAPS so the zone name stands out. This is mainly because multiple zones will be resetting at varied times and I didn't want people to see 2 separate warnings around the same time and accidentally ignore one because they thought it was a warning for the same zone that was just warned about. Plus, I want it to show long names to look a little cleaner.

As for the variables being defined in each script, you may be correct. I am not defining any variables by using "my", so, I guess they are being defined by the settimer command. I kinda figured that these worked on a per-quest basis similar to the "my" setting for variables. The thing I am unsure about is where the actual timers are being calculated and stored. I looked in the "timers" table and I don't see them in there. So, I am guessing they are being ran independently outside of the database in the actual script itself.

I still have more testing to do and refining to my current setup. If the timer names weren't the reason that the Crushbone script was ran in PoTimeB, then I still need to figure out what was. I am leaning towards the way I setup the spawn2 database for the quest NPC. Maybe somehow it is letting that NPC pull scripts from other zone directories, even though that sounds impossible to me lol. This is just a minor issue though and I don't think it will be hard to fix once I find the cause for sure.

Andrew80k
02-27-2008, 10:18 AM
You can use uc to change $zoneln to upper case, ie $ZONELN=uc($zoneln);

Just a thought.

trevius
02-27-2008, 03:37 PM
Oh nice! I will definitely test that one out! Wish I could edit posts to make minor adjustments to my quest submissions. I almost think I should post them in Quest Q&A for a couple of weeks and make sure everything is perfect before submitting them here :P At least when I do post them they actually work. I normally just find minor tweaks to make them better later.

I think most quest submissions are trying to emulate live or have 1 specific purpose, so once they work, they work and don't need replies to make notes or adjustments to them. Many of the quests I have been working on are completely different uses for quests than what they are normally used for. This zone reset quest is more like a code ruleset than a quest. And like any code update, there is always a chance for patches and changes to adjust them :P

trevius
02-28-2008, 04:30 AM
You can use uc to change $zoneln to upper case, ie $ZONELN=uc($zoneln);

Just a thought.

Can't seem to figure out how to get that working. Could you use it in a simple sub EVENT_SAY as an example, please?

AndMetal
02-29-2008, 09:33 AM
You should be able to do it like this, using your code:


sub EVENT_TIMER {
my $zonelnuc = uc($zoneln);
if ($timer eq "warning1") {
quest::stoptimer("warning1");
quest::shout("$zonelnuc will be restarting in 30 minutes. Please zone out before that time.");
}
...
...
...
}



So, you could just need to rename the $zoneln in the rest of the script to $zonelnuc.

trevius
03-03-2008, 08:58 PM
Got the $zoneln working in caps now thanks to AndMetal. Here is the current and hopefully final version of the script:

#############
#Quest Name: 4 Hour Zone Reset Script
#Author: Trevius
#NPC's Involved: Storm Haven
#Items Involved: None
#############
###NPC 1
#Name: Storm Haven (Or whatever your server name Is)
#Race 127 (invisible man), Texture of 0, Size 1, gender of 0, body type 11
#Location: 0,0,-999 of the Nexus
#level: 100
#Type: Quest NPC that resets the zone
#Loot: N/A
#############

sub EVENT_SPAWN {
quest::settimer("nxs_reset",14400);
quest::settimer("nxs_warning1",12600);
quest::settimer("nxs_warning2",13200);
quest::settimer("nxs_warning3",13800);
quest::settimer("nxs_warning4",14100);
quest::settimer("nxs_warning5",14280);
quest::settimer("nxs_warning6",14340);
quest::settimer("nxs_warning7",14395);
}


sub EVENT_TIMER{

my $zonelnuc = uc($zoneln);

if ($timer eq "nxs_warning1"){
quest::stoptimer("nxs_warning1");
quest::shout("$zonelnuc will be restarting in 30 minutes. Please zone out before that time.");}

if ($timer eq "nxs_warning2"){
quest::stoptimer("nxs_warning2");
quest::shout("$zonelnuc will be restarting in 20 minutes. Please zone out before that time.");}

if ($timer eq "nxs_warning3"){
quest::stoptimer("nxs_warning3");
quest::shout("$zonelnuc will be restarting in 10 minutes. Please zone out before that time.");}

if ($timer eq "nxs_warning4"){
quest::stoptimer("nxs_warning4");
quest::shout2("$zonelnuc will be restarting in 5 minutes. Please zone out before that time.");}

if ($timer eq "nxs_warning5"){
quest::stoptimer("nxs_warning5");
quest::shout("$zonelnuc will be restarting in 2 minutes. Please zone out before that time.");}

if ($timer eq "nxs_warning6"){
quest::stoptimer("nxs_warning6");
quest::shout("THIS ZONE WILL BE RESTARTING IN 1 MINUTE! PLEASE ZONE OR LOG OUT NOW!");}

if ($timer eq "nxs_warning7"){
quest::stoptimer("nxs_warning7");
quest::shout2("$zonelnuc is being restarted right now! It will be back immediately, so you can zone back in right away.");}

if ($timer eq "nxs_reset"){
quest::stoptimer("nxs_reset");
kill SEGV => $$;}
}

The spawn setup I had previously was definitely the cause of the zones reporting as resetting other zone names. I set each zone to have an NPC with the same name, but each one has it's own spawn ID now. They all also have their own spawn2 group ID that was created new for each zone. It is working perfectly now.

The only bug I am noticing is that my server now reports more players than it currently has on. It seems to be some kind of connection buildup that is probably created by the resets. When I log in after a high number of players have been on my server all day, I see about half as many players in /who all as I do at the server select screen. Also, a good chunk of them are listed as "0 unknown", which I think means the characters were sent to character select when the zones restarted and the person is still AFK and left their character at character select.

If I can find a way to make players time out from character select, that will resolve that one issue. But, overall, my server seems to be running better than ever. Previously if my server built up enough connections to start getting lag, that lag would never clear even if the player count dropped low again. I would have to reset the server to get lag back to normal. Now with the zone resetters, they seem to bring lag back down to normal after prime time when many players have been on.

Eventually I will look into other ways to further reduce lag, but this seems to be a nice work-around for now :)

trevius
03-11-2008, 12:30 PM
Woot, I didn't even notice till now that my quest made it into the completed section for quests!

I wanted to make a quick note that since I corrected the spawn issue with the NPC that had the quest to reset the zones, my "0 unknown" players on /who all and my server reporting false numbers to the server select issues are both gone! I am not sure what was causing them, but they have completely disappeared now. So, there are no more weird side effects from this quest.

There are 2 other popular servers using my script in at least a few of their zones and they have also reported that this has helped their ghosting and lag issues noticeably. I will continue to investigate those issues, but that will be for another thread. This one is complete now and works 100% perfectly as I intended it with no side effects.

gernblan
04-19-2008, 05:22 AM
Ghosting is not an issue on Linux servers, at least it hasn't been for awhile.

Just FYI.