PDA

View Full Version : Clean Spawn Points



ShortBuss
04-11-2013, 09:56 AM
I've noticed that we have several things showing up as spawn points that should not. This include mounts, Auras, and Mercenaries. This can make the spawn points in your camp very messy if you have auras you refresh or if you use mercenaries or mounts. I found a thread in the archive on this, but looks like it never got implemented:

http://www.showeq.net/forums/archive/index.php/t-6218.html

Here's the patch I have so far. Seems to be working but needs more testing. Uses the flags for aura and mercenary that are already in the spawn structure. Aura was part of "OtherData" and I broke out OtherData in everquest.h to make it clear what is where. This will be helpful for when the values move around after a patch. There is no flag for mount so we have two options. First we can parse the name looking for Mount. This is what was done in the archived thread. But I don't really like that method. The existing method was already looking for horse mounts using race and I stuck with that, for now at least, but it means a lot more races added in.

Let me know if there is any interest in this or any suggestions for changes to it.



Index: src/spawnshell.cpp
================================================== =================
--- src/spawnshell.cpp (revision 784)
+++ src/spawnshell.cpp (working copy)
@@ -601,7 +601,7 @@
}
*/

- if(spawn->otherData & 4) // aura stuff
+ if(spawn->aura) // aura stuff
{
netStream.readText(); // skip 2 variable len strings
netStream.readText();
@@ -710,13 +710,13 @@
spawn->posData[4] = netStream.readUInt32NC();
spawn->posData[5] = netStream.readUInt32NC();

- if(spawn->otherData & 16)
+ if(spawn->hasTitle)
{
name = netStream.readText();
strcpy(spawn->title, name.latin1());
}

- if(spawn->otherData & 32)
+ if(spawn->hasSuffix)
{
name = netStream.readText();
strcpy(spawn->suffix, name.latin1());
Index: src/spawn.cpp
================================================== =================
--- src/spawn.cpp (revision 784)
+++ src/spawn.cpp (working copy)
@@ -435,6 +435,9 @@

setTypeflag(s->bodytype);
setGM(s->gm);
+ setIsMount(calcIsMount(s->race, s->level));
+ setIsMercenary(s->isMercenary);
+ setIsAura(s->aura);

// If it is a corpse with Unknown (NPC) religion.
if ((s->NPC == SPAWN_PC_CORPSE) && (s->deity == DEITY_UNKNOWN))
@@ -979,6 +982,53 @@
d << m_lastName;
}

+bool Spawn::calcIsMount(uint32_t race, uint8_t level)
+{
+ bool isMountRace;
+ switch (race)
+ {
+ case 216: //Horse
+ case 348: //Drogmore
+ case 517: //Nightmare/Unicorn
+ case 518: //Horse
+ case 519: //Nightmare/Unicorn
+ case 594: //Worg
+ case 623: //Wrulon Mount
+ case 625: //Sokokar Mount
+ case 631: //Hydra Mount
+ case 652: //Cliknar Mount
+ case 654: //Spider Mount
+ case 655: //Bear Mount
+ case 656: //Rat Mount
+ case 657: //Sessiloid Mount
+ case 671: //Topiary Lion Mount
+ case 672: //Rot Dog Mount
+ case 673: //Goral Mount
+ case 674: //Selyran Mount
+ case 675: //Sclera Mount
+ case 676: //Braxy Mount
+ case 677: //Kangon Mount
+ case 679: //Wurm Mount
+ case 682: //Helicopter backpack
+ case 684: //Steam Escalator
+ case 709: //Skystrider
+ case 721: //Severed Hand
+ isMountRace = true;
+ break;
+ default:
+ isMountRace = false;
+ break;
+ }
+ if (level == 30 && isMountRace)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
//----------------------------------------------------------------------
// Door
Door::Door(const doorStruct* d)
Index: src/spawnmonitor.cpp
================================================== =================
--- src/spawnmonitor.cpp (revision 784)
+++ src/spawnmonitor.cpp (working copy)
@@ -229,7 +229,7 @@
void SpawnMonitor::checkSpawnPoint(const Spawn* spawn )
{
// ignore everything but mobs
- if ( ( spawn->NPC() != SPAWN_NPC ) || ( spawn->petOwnerID() != 0 ) || (spawn->level() == 30 && spawn->race() == 216) )
+ if ( ( spawn->NPC() != SPAWN_NPC ) || ( spawn->petOwnerID() != 0 ) || spawn->isMount() || spawn->isAura() || spawn->isMercenary() )
return;

QString key = SpawnPoint::key( *spawn );
Index: src/spawn.h
================================================== =================
--- src/spawn.h (revision 784)
+++ src/spawn.h (working copy)
@@ -284,6 +284,12 @@
{ return (raceTeam() == spawn->raceTeam()); }
bool isSameDeityTeam(const Spawn* spawn) const
{ return (deityTeam() == spawn->deityTeam()); }
+ bool isMount() const
+ { return m_isMount; }
+ bool isAura() const
+ { return m_isAura; }
+ bool isMercenary() const
+ { return m_isMercenary; }

// virtual set method overload
void setPos(int16_t x, int16_t Pos, int16_t z,
@@ -323,6 +329,9 @@
void setNPC(uint8_t NPC) { m_NPC = NPC; }
void setTypeflag(uint8_t typeflag) { m_typeflag = typeflag; }
void setGM(uint8_t gm) { m_gm = gm; }
+ void setIsMount(bool isMount) { m_isMount = isMount; }
+ void setIsMercenary(uint8_t isMercenary) {m_isMercenary = (isMercenary != 0); }
+ void setIsAura(unsigned aura) {m_isAura = (aura != 0); }
void setID(uint16_t id) { m_ID = id; }
void setLastName(const char * lastName)
{ m_lastName = QString::fromUtf8(lastName); }
@@ -334,6 +343,7 @@
protected:
void calcRaceTeam();
void calcDeityTeam();
+ bool calcIsMount(uint32_t, uint8_t);

// spawn specific data
QString m_lastName;
@@ -364,6 +374,9 @@
uint8_t m_typeflag;
uint8_t m_animation;
uint8_t m_gm;
+ bool m_isMount;
+ bool m_isMercenary;
+ bool m_isAura;
bool m_considered;
bool m_notUpdated;
};
Index: src/everquest.h
================================================== =================
--- src/everquest.h (revision 784)
+++ src/everquest.h (working copy)
@@ -1053,11 +1053,25 @@
unsigned targetcyclable:1;
unsigned padding1:2;
unsigned trader:1;
- unsigned buyer:1;
+ unsigned padding8:1;
};
int32_t miscData;
};
-/*0000*/ uint8_t otherData; // & 4 - has title, & 8 - has suffix, & 1 - it's a chest or untargetable
+/*0000*/ union
+ {
+ struct
+ {
+ unsigned buyer:1;
+ unsigned offline:1;
+ unsigned aura:1;
+ unsigned padding9:1;
+ unsigned hasTitle:1;
+ unsigned hasSuffix:1;
+ unsigned padding10:1;
+ unsigned padding11:1;
+ };
+ uint8_t otherData;
+ };
/*0000*/ uint32_t race;
/*0000*/ uint8_t charProperties;
/*0000*/ uint32_t bodytype;

ShortBuss
04-12-2013, 09:10 AM
Did some testing on this last night and it seems to be working well. No more spawn points for auras, mercenaries or mounts. All other spawn points seem to still be coming up fine. I'm sure I don't have all the mount races yet, but those can be added as we find them.

purple
04-16-2013, 06:32 AM
That looks like a good patch to my old eyes. That race switch does't look that bad to me if there is no discernable flag for mounts. Do you have to do the level == 30 part?

Are there are handlers that modify race? The illusion handler or the shroud handler? Any of the spawn update handlers? I guess things don't ever change into a mount or an aura so maybe it's not a big deal.

Helicopter backpack!??!

ShortBuss
04-16-2013, 09:12 AM
There are some specific races which are mount only. For example: Spider Mount. However there are others that can be mounts or non-mounts. For example, Worg. The level = 30 check is just a safety in case a race is for both mount and other NPCs to prevent removing the spawn point for a non-mount instance of the race.

I hadn't thought to check for other flags that may indicate mount. I don't expect to find anything, but it's at least worth a look.

I didn't get the real name for "Helicopter backpack". As I was testing things out I noted there was a player with mount I didn't have raceID for yet. I added the ID then headed over to see what the mount was. I saw it looked like a backpack with helicopter prop on top, but the player zoned before I could get it's real name from his buff. It's not one I was able to find in station cash store, so I'm not sure where else I may look for proper name.

ShortBuss
04-18-2013, 02:01 PM
Well I parsed out all the spawns from a 5 hour log file looking at every variable pulled out by fillSpawnStruct. There is no unique variable or combination of variables that can be used to uniquely identify a mount based on those variables. There are some common values among mounts, like State is always 100 or 102 and Body Type is always 21, but those things are also true of other NPCs that aren't mounts. It may be something that isn't parsed out by fillSpawnStruct (one of the skips maybe) could help, but I didn't dig that far. This leaves me with 2 options:
1. Parse on the name looking for something ending in Mount.
2. What I have done above which is level = 30 and race = a mount race. I was able to add in another 5 or so mount races based on this last parse.


case 216: //Horse
case 348: //Drogmore
case 492: //Horse
case 517: //Nightmare/Unicorn
case 518: //Horse
case 519: //Nightmare/Unicorn
case 583: //Kirin
case 584: //Puma
case 594: //Worg
case 597: //Cragslither
case 598: //Wrulon
case 623: //Wrulon Mount
case 625: //Sokokar Mount
case 631: //Hydra Mount
case 652: //Cliknar Mount
case 654: //Spider Mount
case 655: //Bear Mount
case 656: //Rat Mount
case 657: //Sessiloid Mount
case 671: //Topiary Lion Mount
case 672: //Rot Dog Mount
case 673: //Goral Mount
case 674: //Selyran Mount
case 675: //Sclera Mount
case 676: //Braxy Mount
case 677: //Kangon Mount
case 679: //Wurm Mount
case 680: //???
case 682: //Helicopter backpack
case 684: //Steam Escalator
case 709: //Skystrider
case 720: //???
case 721: //Severed Hand


Maybe I'm crazy but I still prefer the level and race option over parsing the name.

purple
04-19-2013, 03:25 PM
Yeah I think that is your best bet too. It just is kludgy. That doesn't necessarily mean don't do it!

Something has to hook a person to a mount. It would be interesting to collect packet dumps for:
1) Zoning into an empty-ish zone to that has someone in it who is on horse compared to zoning into an empty-ish zone that has the same guy not on a horse
2) What packets show up when someone summons a horse? Do you receive movements packets for both the horse and the person? Just the server combine the mount + player into a single mob?

I wonder if the mount code is specialized pet code and there is an owner spawn id somewhere.

Anyways, don't take my yammering too seriously. What you have is good enough to check in.

ShortBuss
04-19-2013, 03:39 PM
Hmm, I hadn't thought about testing it that way. I may go ahead with it as is for now, but I still want to investigate further. Guild Hall makes a good empty place to play in now. I'll sit a char in and see the difference on the zone in packets between them being mounted vs not mounted. You're right in that there has to be something tying the two of them together. Otherwise we'd never get the graphic of the person sitting on the horse.

ShortBuss
04-19-2013, 05:14 PM
The only difference in the spawn structure between a mounted and unmounted player is in the bytes in the position data. Checking the position data value the only change is in Z, which isn't surprising since a mounted player is a little higher off the ground. Even checked the padding in the position data and that didn't change. This is comparing the full log entries, so can say for sure nothing in the player's spawn structure ties it to the mount. This means the mount's spawn structure must tie it to the player. I expect the value is hidden somewhere in the bytes that are skipped reading the spawn structure. Maybe I can find the player's ID in there.