Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Server Code Submissions

Reply
 
Thread Tools Display Modes
  #1  
Old 07-21-2011, 10:32 AM
image
Demi-God
 
Join Date: Jan 2002
Posts: 1,290
Default Faylevator Lifts

This although a hardcode provides a little better response with the switches that are used for the fay lifts in gfaydark. It isn't perfect but they never were on live either. As it was before this change it requires about 4 clicks to get the lift moving, after it should take no more than 2.

doors.h

Code:
bool	IsDoorOpen() { if ( ( !strcasecmp(GetDoorName(),"FELE2") || !strcasecmp(GetDoorName(),"FAYLEVATOR") ) && door_param == 1 ) return false; else return isopen; }
__________________
www.eq2emu.com
EQ2Emu Developer
Former EQEMu Developer / GuildWars / Zek Seasons Servers
Member of the "I hate devn00b" club.
Reply With Quote
  #2  
Old 07-21-2011, 08:46 PM
pfyon's Avatar
pfyon
Discordant
 
Join Date: Mar 2009
Location: Ottawa
Posts: 495
Default

I remember 2 on live. It only seemed to trigger if you went from (example) state 1 to state 2, and not state 2 to state 1.
Reply With Quote
  #3  
Old 07-22-2011, 12:32 AM
ItchybottomX
Fire Beetle
 
Join Date: Jul 2011
Posts: 7
Default

If someone has a live account, I suggest looking into OP_ClickDoor for a better fix.

Code:
struct ClickDoor_Struct {
/*000*/	int8	doorid;
/*001*/	int8	unknown001;		// This may be some type of action setting
/*002*/	int8	unknown002;		// This is sometimes set after a lever is closed
/*003*/	int8	unknown003;		// Seen 0
/*004*/	int8	picklockskill;
/*005*/	int8	unknown005[3];
/*008*/ int32	item_id;
/*012*/ int16	player_id;
/*014*/ int8	unknown014[2];
/*016*/
};
Reply With Quote
  #4  
Old 07-22-2011, 01:48 AM
trevius's Avatar
trevius
Developer
 
Join Date: Aug 2006
Location: USA
Posts: 5,946
Default

I haven't messed with the GFay lifts too much, but I did to a bit of testing on the lifts in Stonehive. I added a debug in EVENT_CLICKDOOR that reported the doorid when it was clicked and saw some weird output that I can't really explain. The lift would go up after a click or 2, but it would then spam like 4 times that it was clicked again when it was time for the lift to come back down. I looked into it in the source a bit and didn't see anything that stood out, but maybe a packet collect would give better info into what is happening. Door packets aren't overly complex, so it probably wouldn't be too hard to resolve the lift issues, it would just take time to look into it properly.
__________________
Trevazar/Trevius Owner of: Storm Haven
Everquest Emulator FAQ (Frequently Asked Questions) - Read It!
Reply With Quote
  #5  
Old 07-22-2011, 08:03 AM
image
Demi-God
 
Join Date: Jan 2002
Posts: 1,290
Default

Yeah, I am sure someone is going to pounce all over that to get a live collection

Someone else is welcome to spend the time to fix the structure, doesn't seem worth the trouble for a few select objects that work different than most doors in the game.
__________________
www.eq2emu.com
EQ2Emu Developer
Former EQEMu Developer / GuildWars / Zek Seasons Servers
Member of the "I hate devn00b" club.
Reply With Quote
  #6  
Old 07-22-2011, 06:05 PM
ItchybottomX
Fire Beetle
 
Join Date: Jul 2011
Posts: 7
Default

on the client side of things on EQEMU:

unknown001 returns 1 or 2 normally (not sure why), or 231 with a lockpick item in hand
unknown002 returns 0 normally, or 64 with a lockpick item in hand

The other unknowns return no data within bounds specified of sizeof(ClickDoor_Struct)

Another option to fix this not involving someone going on live and getting me (or someone else) collects for this, would be to use player.pl for the triggers.

Just verify the open/close state on the lifts, and force them the other direction on a click. We already do that for doors that have multiple parts -- but I'm thinking getting the structure proper is far more elegant.

edit: also noticed that in the database, for DoorStructs we don't have a column for state_at_spawn. That could also be helpful since our lifts are inverted. Start them closed at spawn, but still inverted.
Reply With Quote
  #7  
Old 07-24-2011, 08:50 AM
joligario's Avatar
joligario
Developer
 
Join Date: Mar 2003
Posts: 1,497
Default

Speaking of the door spamming in the clickdoor message:
I believe it is because of NPCs opening doors. You can do the same thing in PoM castle. An NPC is standing next to a torch and it spams the door opening message. That may be what screws with the lifts as well.
Reply With Quote
  #8  
Old 07-24-2011, 06:18 PM
image
Demi-God
 
Join Date: Jan 2002
Posts: 1,290
Default

Quote:
Originally Posted by joligario View Post
Speaking of the door spamming in the clickdoor message:
I believe it is because of NPCs opening doors. You can do the same thing in PoM castle. An NPC is standing next to a torch and it spams the door opening message. That may be what screws with the lifts as well.
This could be, however I think Trevius is referring to a player clicking lifts. I have seen the similar behavior, for some reason the client will spam the door clicks in certain circumstances.

But as I said before it just didn't seem like worth the effort for such a small group of objects. If someone *really* wants to you could just change this to be some inverse boolean and check the door name at the instantiation of it.

In any case I assure this is a good place to start looking for the lift issue
__________________
www.eq2emu.com
EQ2Emu Developer
Former EQEMu Developer / GuildWars / Zek Seasons Servers
Member of the "I hate devn00b" club.
Reply With Quote
  #9  
Old 07-25-2011, 12:09 AM
blackdragonsdg
Dragon
 
Join Date: Dec 2008
Location: Tennessee
Posts: 654
Default

Quote:
Originally Posted by ItchybottomX View Post
Another option to fix this not involving someone going on live and getting me (or someone else) collects for this, would be to use player.pl for the triggers.

Just verify the open/close state on the lifts, and force them the other direction on a click. We already do that for doors that have multiple parts -- but I'm thinking getting the structure proper is far more elegant.
Before someone wastes their time trying to use player.pl to force the doors open and closed they will need to fix the doors code.
Code:
void Doors::ForceOpen(Mob *sender)
{
    EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct));
	MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer;
	md->doorid = door_id;
	md->action = OPEN_DOOR;
	entity_list.QueueClients(sender,outapp,false);
	safe_delete(outapp);

    if(!isopen) {
        close_timer.Start();
        isopen=true;
    }
    else {
        close_timer.Disable();
        isopen=false;
    }
}

void Doors::ForceClose(Mob *sender)
{
    EQApplicationPacket* outapp = new EQApplicationPacket(OP_MoveDoor, sizeof(MoveDoor_Struct));
	MoveDoor_Struct* md=(MoveDoor_Struct*)outapp->pBuffer;
	md->doorid = door_id;
	md->action = OPEN_DOOR;
	entity_list.QueueClients(sender,outapp,false);
	safe_delete(outapp);

    if(!isopen) {
        close_timer.Start();
        isopen=true;
    }
    else {
        close_timer.Disable();
        isopen=false;
    }
}
Doors::ForceClose() and Doors::ForceOpen() should not be identical. A fix was suggested for that particular problem but I never tested it on the lifts in greater faydark as I was working with another set of lifts at the time. More on that can be found here: http://www.eqemulator.org/forums/sho...light=Vergalid
Reply With Quote
  #10  
Old 07-25-2011, 07:39 AM
image
Demi-God
 
Join Date: Jan 2002
Posts: 1,290
Default

ForceOpen may be used by NPC's on pathing - however, ForceClose is only used by quest files. These are not related to what we are addressing here.
__________________
www.eq2emu.com
EQ2Emu Developer
Former EQEMu Developer / GuildWars / Zek Seasons Servers
Member of the "I hate devn00b" club.
Reply With Quote
  #11  
Old 06-06-2012, 09:19 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default

(I wrote this offline last night and realize that some of my points have already been implied above.)


When I play around with the Crescent Reach lifts, the cycles all begin and end on the bottom. I'm assuming this is
the closed state since they work with the way they are coded (yes, I am aware of the difference in coding for
triggertypes 1/255 versus 0/0.)

However, GFay lifts begin at the top, then cycle down and back up. Is it possible that the default state should be
open and not closed for them? (Are these the only ones in-game that start at the top and/or still don't currently
work properly?) And does the client send the actual door state or just a click event for activation?

I'm also assuming that the GFay 'levers' are in a closed state since they're all down, like Crescent's (except for
orc-top for some reason - SoF client.)

(Side note: you can change the direction of GFay and Crescent lifts, but not the non-triggered sliding doors that
I tested, while they're in operation with multiple clicks. Is this expected behavior?)


If you let all of the timers reset between clicks (waiting ~18 seconds (down), ~18 seconds (up), and 5 seconds
(close_timer)), the lifts themselves never activate. Only when you click multiple times during this ~41 second
period (first ~18 seconds most likely) do they ever work. This sounds like a logic conflict in the state of the
doors (lifts) themselves and not a fault in the code, especially since 'normally closed' doors seem to work
correctly and the Crescent lifts work using essentially the same logic.


I want to tinker around with the code for this, but everything is coded for instant open, timer close. I might try
adding a conditional to 'SetDoorState(i.e., ! doorid = (one of these: 69, 77, 80) ? true : false)' in the
'close_timer' function and some other checks in 'HandleClick' and 'Process' to see if I get any change in lift
operation for the specified lift id.

(Thought: If the client sends the lift state (as open when up) after a move action, then ::Process is turning off
the 'close_timer' when the lift is up (called by handle acutation - maybe it should trigger closed instead) and
setting the state to closed with no move action associated with it..which is why the lift doesn't come down after
the close timer should be processed and without multiple clicks 'fooling' the server and client about the logic
state of the door. I could be wrong...) (The close timer code is expecting the door to be open, not already
closed.)

Does anyone happen to already have any data showing actions and states from the client? I'd like to set up a
truth table based on doors states and events, and then check it against the code logic to determine what the
actual resting (initial) states should be. I haven't gotten to the point where I can collect packet info and
understand what's going on there just yet.



I'm going to tinker around with this for awhile, but if anyone with more experience than I wants to add suggestions,
please feel free to.


U
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #12  
Old 06-07-2012, 09:38 AM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default Test Results & Analysis

I ran a few tests and I believe that what I was saying about the default 'open' state is true, only in regards to server-side
code though. I don't believe the client is involved at all with the exception of a click event. I'm going to add some 'door check'
code to 'HandleClick' next, to handle the GFay lifts and see if that's successful. If it is, I'll work on a suggestion/code
submission for this. (Do you guys have a list of 'broken' doors that I can check with this test code on my server to determine
their operating states?)


For this test, I added 'sender->Message()' code at four points and moved the 'clientqueue' statement just below the door state/timer
conditional check instead of above it. I had to move it to get the status at this point since the packet is sent to the client
before this action occurs currently (code-wise.)

This is what the code move looks like:

Code:
// entity_list.QueueClients(sender, outapp, false); // unremark after test

if(!IsDoorOpen() || (opentype == 58))
{
	close_timer.Start();
	SetOpenState(true);
	[test code]
}
else
{
	close_timer.Disable();
	SetOpenState(false);
	[test code]
}

entity_list.QueueClients(sender, outapp, false); // delete after test
This is the [test code] that I used for the check:

Code:
if (isopen) {
	if (close_timer.Enabled()) {
		sender->Message(4, "[<testpoint>] door:%i-><action>(ds:O|ti:E)", door_id);
	}
	else {
		sender->Message(4, "[<testpoint>] door:%i-><action>(ds:O|ti:D)", door_id);
	}
}
else {
	if (close_timer.Enabled()) {
		sender->Message(4, "[<testpoint>] door:%i-><action>(ds:C|ti:E)", door_id);
	}
	else {
		sender->Message(4, "[<testpoint>] door:%i-><action>(ds:C|ti:D)", door_id);
	}
}
I was running into issues crashing the zone and created the above [test code] before I realized that my string was too long. I just
left it in place since it worked, but this is an untested line that could probably be used instead (if it works...):

Code:
sender->Message(4, "[<testpoint>] door:%i-><action>(ds:%s|ti:%s)", door_id, ! isopen ? "O" : "C", ! close_timer.Enabled() ? "E" : "D");
In the above code:

<testpoint> is where in the code the test originates
"enter" - code inserted just before the LDoN door check
"1/255" - code inserted inside of triggered door check, after 'md->action = <action>'
"0/0" - code inserted inside of unlocked door check, after 'md->action = <action>'
"exit" - code inserted inside of SetOpenState([t/f])/close_timer.[e/d] code, after command lines

"door:%i" is the current value of 'door_id'

<action> is what the major action is near where the test originates
"start" - no 'door processing' has occurred
"open" - after line 'md->action = OPEN_DOOR'
"close" - after line 'md->action = CLOSE_DOOR'
"queue" - last action performed before packet queued to client

"ds:%s" is the door state value from 'isopen' [O|C] ("O" is open [t], "C" is closed [f])

"ti:%s" is the 'close_timer' enabled state [E|D] ("E" is enabled [t], "D" is disabled [f])


Now to what I'm sure you've been wait for... The results!

I tried this test on all of the lower lift actuators at Kelethin with the same results, and the inner/bottom lift in Crescent Reach
proper. At least one minute was allowed to pass before performing each GFay lift check. (They're different, yes, but they're also
the same..read the analysis below to find out why.)


Code:
(CRESCENT - DOOR 1, ONE-CLICK, LIFT ACTIVATED)+++
<Click 1>
[enter] door:10->start(ds:C|ti:D)  [line 1]
[0/0] door:10->open(ds:C|ti:D)     [line 2]
[exit] door:10->queue(ds:O|ti:E)   [line 3]
[enter] door:1->start(ds:C|ti:D)   [line 4]
[1/255] door:1->open(ds:C|ti:D)    [line 5]
[0/0] door:1->open(ds:C|ti:D)      [line 6]
[exit] door:1->queue(ds:O|ti:E)    [line 7]


(GFAY - DOOR 80, ONE-CLICK, NO LIFT ACTIVATION)---
<Click 1>
[enter] door:81->start(ds:C|ti:D)  [line 8]
[0/0] door:81->open(ds:C|ti:D)     [line 9]
[exit] door:81->queue(ds:O|ti:E)   [line 10]
[enter] door:80->start(ds:C|ti:D)  [line 11]
[0/0] door:80->open(ds:C|ti:D)     [line 12]
[exit] door:80->queue(ds:O|ti:E )  [line 13]

(GFAY - DOOR 80, TWO-CLICKS, NO LIFT ACTIVATION)---
<Click 1>
[enter] door:81->start(ds:C|ti:D)  [line 14]
[0/0] door:81->open(ds:C|ti:D)     [line 15]
[exit] door:81->queue(ds:O|ti:E)   [line 16]
[enter] door:80->start(ds:C|ti:D)  [line 17]
[0/0] door:80->open(ds:C|ti:D)     [line 18]
[exit] door:80->queue(ds:O|ti:E)   [line 19]

<Click 2>
[enter] door:81->start(ds:O|ti:E)  [line 20]
[0/0] door:81->close(ds:O|ti:E)    [line 21]
[exit] door:81->queue(ds:C|ti:D)   [line 22]

(GFAY - DOOR 80, THREE-CLICKS, LIFT ACTIVATED)+++
<Click 1>
[enter] door:81->start(ds:C|ti:D)  [line 23]
[0/0] door:81->open(ds:C|ti:D)     [line 24]
[exit] door:81->queue(ds:O|ti:E)   [line 25]
[enter] door:80->start(ds:C|ti:D)  [line 26]
[0/0] door:80->open(ds:C|ti:D)     [line 27]
[exit] door:80->queue(ds:O|ti:E)   [line 28]

<Click 2>
[enter] door:81->start(ds:O|ti:E)  [line 29]
[0/0] door:81->close(ds:O|ti:E)    [line 30]
[exit] door:81->queue(ds:C|ti:D)   [line 31]

<Click 3>
[enter] door:81->start(ds:C|ti:D)  [line 32]
[0/0] door:81->open(ds:C|ti:D)     [line 33]
[exit] door:81->queue(ds:O|ti:E)   [line 34]
[enter] door:80->start(ds:O|ti:E)  [line 35]
[0/0] door:80->close(ds:O|ti:E)    [line 36]
[exit] door:80->queue(ds:C|ti:D)   [line 37]

If you notice in the 'Crescent' test, this is how a triggered door should operate. Line 3 shows where the status has changed on
the actuator. Line 6 shows an apparent 'double-true' condition, but end result is not affected. (If the gm flag was set, I think
you could actually get a 'triple-true' condition..but again the end result is not affected.) Line 7 is the actual state change
that shows the lift (door 1) has activated. (Lines 5 and 6 both perform the same action, but one just overwrites the other before
the command is pushed to the client. That occurs after the [exit] <testpoint>.)

In the 'Greater Fay' test series, I believe that I can prove my theory about what is causing the 'wacky' lift performance.
Obviously, Line 12 of the first test shows the 'open' client action with current states of [closed|disabled]. Line 13 shows that
the server thinks the door is now open.

In the second test, lines 14 to 19 are the same as in the first test. With <Click 2>, door 81 (the actuator) shows that it is
currently [open|enabled]. But, what happened to the response from door 80? Line 19 answers that. It is set to an open state.
When the code processes door 80 during the second click, no !IsDoorOpen() conditional code is processed. And because my test code
is located exclusively inside of closed door checks, it never get processed.

With the third test... This is where it gets interesting. Lines 23 to 31 are the same results as in the 'two-click' test. Notice
how the states in <Click 1> show the same states at the corresponding <testpoints> in each door? Now notice how <Click 2> shows
that door 81 has flipped all of its states.

So, why does the lift work on the third click? Thank you <Click 2>! It changed the state of door 81, but not door 80 because it
was not an 'open' request. <Click 2> was processing a close request for door 81 and door 80's states were not changed. Now, with
<Click 3>, the door (lift) is in a state to be lowered. As door 81 'opens', it triggers door 80 again, as it did in <Click 1>.
This time, however, door 80 is in an 'open' state and the conditional checks tell the door to close 'md->action = CLOSE_DOOR').
And, voila! The lift now comes down and the states are reset to the original resting state in line 37 (unless you played with the
acutator and messed up the states.)

The close_timer event handler might normally allow the lift to actually come down after 5 seconds, but the hidden processing in
<Click 2> is seeing that the door is open and doesn't seem to mark the door as closed server-side and send the 'CLOSE_DOOR'
event to the client, or it is not being triggered at all.


The problem: Greater Faydark lifts are in a default state of 'Open' and a 'md->action = CLOSE_DOOR' is required to make them work.


Now that we can see what is causing the problem, how do we fix it? I have a few ideas, but I'm still working on that...


U
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
  #13  
Old 06-08-2012, 08:04 PM
Uleat's Avatar
Uleat
Developer
 
Join Date: Apr 2012
Location: North Carolina
Posts: 2,815
Default One-click GFay lifts: Check (maybe)

I fixed my mistake in the test code. My c++ ignorance was showing..I mistakingly used '!' as 'If' in the single line conditional.
(I know that it's the 'not' operator, !duh, err, duh!.) Test code now shows proper state, and I added some additional 'value' reports.


I can operate the GFay lifts with one click now, and they can be ridden as well. There's still something in the code causing state
conflict on the 'triggered' actions, but I'm looking at that now. This problem may be what was causing that erratic behavior that
you saw Stonehive Trev...

(Are these calls thread-safe?)

In addition, I was using the melee key to insert 'click' separators at one point and got some very strange report for door_id. (This
was before I added the 'fix' code.) It reported the value of door_id as some 8~12 digit number on some iterations. I didn't write it
down, but it definitely exceeded the door_id range and even the 'door' table ID range. Haven't seen it since fix added though.

(I'll check as many different door types as I can before I submit the code.)


This is going to end up being a bug. Should I bump this conversation to 'bug report' or to 'code submission'?

(pre-p.s. Cave_Dude, GFaydark door 78 (orc-top) is set to invert_state = 1. Can you look into setting it to '0' for published peq, like
the other actuators for GFay lifts? Lifts themselves need to stay '1' though.)


U
__________________
Uleat of Bertoxxulous

Compilin' Dirty
Reply With Quote
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump

   

All times are GMT -4. The time now is 09:18 AM.


 

Everquest is a registered trademark of Daybreak Game Company LLC.
EQEmulator is not associated or affiliated in any way with Daybreak Game Company LLC.
Except where otherwise noted, this site is licensed under a Creative Commons License.
       
Powered by vBulletin®, Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Template by Bluepearl Design and vBulletin Templates - Ver3.3