Go Back   EQEmulator Home > EQEmulator Forums > Development > Development::Development

Development::Development Forum for development topics and for those interested in EQEMu development. (Not a support forum)

Reply
 
Thread Tools Display Modes
  #1  
Old 10-03-2009, 01:50 AM
Pend
Fire Beetle
 
Join Date: Sep 2009
Posts: 16
Default Spirit Shrouds

I spent a few days on this since it didn't seem there had been any work in this area.

I haven't found the real gems of this feature yet, but I was able to decode a few opcodes related to it so far. Specifically, the Shroud Progression window, as well as the tree-list part of the Shroud Selection window. Haven't found the packet to actually transform yet, nor have I found the packet to fill out the ability/stats details of the Shroud Selection window.

I figured I'd post what I have and see if anyone can fill in some more, especially considering I may be distracted of late playing on Project1999 . The following applies to Titanium only.

Opcodes
OP_ShroudSelectionWindow=0x65b1
OP_ShroudProgressionUpdate=0x4625
OP_ShroudBankEmpty=0x455f
OP_ShroudUnknown1=0x6d32 #size=8
OP_ShroudUnknown2=0x18cb #size=?
OP_ShroudUnknown3=0x1573 #size=?
OP_ShroudUnknown4=0x11cd #size=?
OP_ShroudUnknown5=0x7f63 #size=?

The first three I'm sure about. I'm suspicious that the last one is mischaracterized as OP_LockoutTimerInfo in the release version of patch_Titanium.conf.

Structures
OP_ShroudBankEmpty
I think OP_ShroudBankEmpty is pretty simple and requires no structure. It's sent as an opcode-only and merely prints out the message:
4558 "The Shroud Bank window was not opened, as there were no items that could be transferred from your previous form."

There are no conditionals that get in the way of that message being printed for that opcode, so I think that's all it does.

OP_ShroudProgressionUpdate
Code:
#pragma pack(1)
struct ShroudProgressionUpdate
{
	uint32 numProgressions;
	char progressionString[1];
};
#pragma pack()
numProgressions is the number of progressions contained within the packet. progressionString is a variable-length string describing the progressions. This string has several parts, each delimited by a 0x7 character. Here's an example string:

Code:
char progression_str[] =	
	"PROGRESSION" "\007"	 // must be the word 'PROGRESSION'
	"1" "\007"				 // unknown integer
	"Aberrations" "\007"	 // Progression name
	"Imp Wizard 5" "\007"	 // Class name
	"3" "\007"				 // How many unlocked?
	"14" "\007"				 // How many total?
	"Evil Eye Psion" "\007"  // Next branch name
	"Imp Wizard 10" "\007"	 // Next class name
	"6" "\007"				 // Percentage complete
							
	"PROGRESSION" "\007"	 // Here follows a second
	"2" "\007"				 //  progression described in
	"Animals" "\007"		 //  the same packet.
	"Bear Beast 5" "\007"	
	"7" "\007"				
	"12" "\007"				
	"Wolf Beast" "\007"		
	"Bear Beast 10" "\007"	
	"25" "\007"				
	;
OP_ShroudSelectionWindow
Code:
#pragma pack(1)
struct ShroudSelectionWindow
{
	uint32 triggerNPCID;
	uint32 numShroudBankItems;
	uint32 unknown2;
	char shroudSelectionTreeString[1];
};
#pragma pack(0)
triggerNPCID is the ID of the NPC which was used to trigger the shroud selection window. eqgame.exe apparently hard-codes a maximum distance the player can be away from this NPC in order for the window to open, or else they'll get this string printed:
4555 "You cannot be transformed into a monster if you get that far."

triggerNPCID can be set to the player's own ID, in which case it'll always work.

numShroudBankItems is the number of items in the player's shroud bank. If this is anything but 0, eqgame.exe will not open the shroud selection window and will instead print the following string:
4557 "You must empty your Shroud Bank before you can polymorph again."

shroudSelectionTreeString works similarly to the string in OP_ShroudProgressionUpdate. It is a multi-part variable length string with 0x7 delimiters that looks like this:

Code:
char shroudselect_str[] =
	"PROGRESSION" "\007"	// 'PROGRESSION'
	"1" "\007"				// unknown integer
	"Aberrations" "\007"	// Progression name
	"2" "\007"				// unknown integer
	"BRANCH" "\007"			// 'BRANCH'
	"3" "\007"				// unknown integer
	"Imp Wizard" "\007"		// Branch name
	"4" "\007"				// unknown integer
	"100" "\007"			// Percentage complete
	"TEMPLATE" "\007"		// 'TEMPLATE'
	"Imp Wizard 5" "\007"	// Template name
	"5" "\007"				// Template level
	"5" "\007"				// UniqueID for this template
	"1" "\007"				// 1=there's more, 0=end

	"TEMPLATE" "\007"		// another template
	"Imp Wizard 10" "\007"
	"10" "\007"
	"6" "\007"
	"1" "\007"
	"TEMPLATE" "\007"		// another template
	"Imp Wizard 15" "\007"
	"15" "\007"
	"7" "\007"
	"1" "\007"
	"BRANCH" "\007"			// start a new branch
	"8" "\007"
	"Evil Eye Psion" "\007"
	"9" "\007"
	"50" "\007"
	"TEMPLATE" "\007"		// new branch's template1
	"Evil Eye Psion 5" "\007"
	"5" "\007"
	"10" "\007"
	"1" "\007"
	"TEMPLATE" "\007"		// new branch's template2
	"Evil Eye Psion 10" "\007"
	"10" "\007"
	"11" "\007"
	"1" "\007"
	"TEMPLATE" "\007"		// etc.
	"Evil Eye Psion 15" "\007"
	"15" "\007"
	"12" "\007"
	"0" "\007"				// end it with a 0
	;
Fairly straightforward. When the player is presented with the selection window, the game immediately highlights one of the templates and issues a 0x0000 opcode to the game client containing a 4-byte value. That 4-byte value is the UniqueID identified in the string for that template. Same happens if a user clicks on one of the other progressions/branches/templates in the window. Presumably, this is what is supposed to trigger the server to send another packet describing that template (stats, class, abilities, etc.) but that's the elusive opcode I haven't found yet.

Last edited by Derision; 05-15-2010 at 05:16 PM..
Reply With Quote
  #2  
Old 10-04-2009, 02:28 PM
Pend
Fire Beetle
 
Join Date: Sep 2009
Posts: 16
Default

Confirmed that OP_ShroudUnknown5=0x7f63 is the same as OP_ShroudProgressionUpdate=0x4625 in terms of what it does and what its packet structure looks like. Basically, both opcodes perform the same function, except that 0x7f63 does one tiny extra step that doesn't seem to have anything to do with the packet contents (perhaps a window reset?).

This also confirms that patch_Titanium.conf mischaracterizes 0x7f63 as OP_LockoutTimerInfo.
Reply With Quote
  #3  
Old 10-04-2009, 06:42 PM
KLS
Administrator
 
Join Date: Sep 2006
Posts: 1,348
Default

I have nothing to add at the moment and can't really poke around at it yet because I'm working on something else: but it's quite interesting.
Reply With Quote
  #4  
Old 10-04-2009, 10:56 PM
Pend
Fire Beetle
 
Join Date: Sep 2009
Posts: 16
Default

Opcodes
OP_ShroudUnknown4=0x11cd #size=?

This was a mistake on my part. Didn't mean to include this in list of shroud-related opcodes.

OP_ShroudUnknown2=0x18cb #size=?

Has been decoded:

OP_ShroudSelEquipDetail=0x18cb

Structures
OP_ShroudSelEquipDetail
Code:
#pragma pack(1)
struct ShroudSelItemDescription
{
	sint32 UniqueID;
	uint32 unknown2;
	uint32 pktSize;
	uint32 serializedItem[1];
};
#pragma pack()
UniqueID is the ID sent for the currently selected monster template which was set during the OP_ShroudSelectionWindow packet.

unknown2 must be -1 (ie. 0xFFFFFFFF).

pktSize = the entire size of serializedItem plus the size of pktSize itself.

serializedItem is a variable-length serialized data stream generated by the Titanium::SerializeItem(...) function.

What this opcode/packet does is display item details, presumably for a currently selected item, in the Shroud Selection window.

You'll notice I made UniqueID an signed int here. This is because eqgame.exe will "UniqueID = -(UniqueID);" if it receives a UniqueID in the OP_ShroudSelectionWindow packet that is less than 0 (ie. >0x7FFFFFFF).
Reply With Quote
  #5  
Old 10-04-2009, 11:15 PM
Pend
Fire Beetle
 
Join Date: Sep 2009
Posts: 16
Default

OP_ShroudUnknown3=0x1573

This one has been most problematic to reverse engineer. It's almost as if the server needs to be directly aware of some object pointer offsets found in eqgame.exe. One thing I found by investigating this was that the value of UniqueID in the above Opcodes cannot be random.

Code:
.text:004FF9C9 sub_4FF9C9 proc near                    ; CODE XREF: sub_4244BA+Ap
.text:004FF9C9                                         ; sub_42EC50+Dp ...
.text:004FF9C9
.text:004FF9C9 arg_0= dword ptr  8
.text:004FF9C9
.text:004FF9C9 push    esi
.text:004FF9CA mov     esi, [esp+arg_0]
.text:004FF9CE mov     eax, esi
.text:004FF9D0 xor     edx, edx
.text:004FF9D2 div     dword ptr [ecx+4]
.text:004FF9D5 mov     eax, [ecx]
.text:004FF9D7 mov     eax, [eax+edx*4]
.text:004FF9DA jmp     short loc_4FF9E4
.text:004FF9DC ; ---------------------------------------------------------------------------
.text:004FF9DC
.text:004FF9DC loc_4FF9DC:                             ; CODE XREF: sub_4FF9C9+1Dj
.text:004FF9DC cmp     [eax+4], esi
.text:004FF9DF jz      short loc_4FF9E8
.text:004FF9E1 mov     eax, [eax+8]
.text:004FF9E4
.text:004FF9E4 loc_4FF9E4:                             ; CODE XREF: sub_4FF9C9+11j
.text:004FF9E4 test    eax, eax
.text:004FF9E6 jnz     short loc_4FF9DC
.text:004FF9E8
.text:004FF9E8 loc_4FF9E8:                             ; CODE XREF: sub_4FF9C9+16j
.text:004FF9E8 pop     esi
.text:004FF9E9 retn    4
.text:004FF9E9 sub_4FF9C9 endp
This subroutine gets used frequently. For the opcode in question, the instruction at 004FF9D2 is problematic:
div dword ptr [ecx+4]

This essentially takes our UniqueID, divides it by 0x17 and only uses the remainder. (UniqueID % 23) It then multiplies by 4 (it's probably doing pointer math), and offsets a pointer by that amount and grabs the value at that new location:
.text:004FF9D7 mov eax, [eax+edx*4]

That value must be non-zero:
.text:004FF9E4 test eax, eax
.text:004FF9E6 jnz short loc_4FF9DC

Then, we assume that value is yet another pointer and compare the second uint32 at the pointer's destination with our original UniqueID:
.text:004FF9DC cmp [eax+4], esi

If we don't find it, we increment our pointer by two unit32s and try the loop back to the non-zero check and do it again.
.text:004FF9DF jz short loc_4FF9E8
.text:004FF9E1 mov eax, [eax+8]

All of this means that the UniqueID is much more than just a UniqueID. It's also an offset for a pointer that expects to find the same offset value somewhere in a structure at its destination.

Its giving me a headache.

Now, I did find only one such possible UniqueID that would satisfy this algorithm. The problem is, that UniqueID was 0x8800001F. As mentioned in a prior post, this value makes an invalid UniqueID because this is < 0 and becomes 0x77FFFFE1 before being saved by the client. :(

Best I can tell, my real problem may be that something hasn't yet been set in the object I'm referencing here. (Faced similar problems getting the other opcodes to work--if the shroud selection window weren't open when the opcode was sent, a subroutine would return a 0 result because an object lookup would fail.)

At this time, I'm not sure what else I need to send to get that object reference to be valid.

Alas, I'll keep hacking away at it.

One last note about this one: the contents of the packet aren't even referenced by this point, but this subroutine's failure cascades into the entire packet being discarded. The UniqueID in this problem is referring to the UniqueID of the currently highlighted template in the shroud selection window. The window must be open for this opcode to even get this far, however. Of that I am certain. So, too, am I certain that OP_ShroudUnknown1=0x6d32 is also handled by this window.
Reply With Quote
  #6  
Old 10-04-2009, 11:41 PM
Pend
Fire Beetle
 
Join Date: Sep 2009
Posts: 16
Default

One more one more note.

I'm pretty sure OP_ShroudUnknown3 is an ability description opcode in the same fashion that OP_ShroudSelEquipDetail is an item description opcode. Why? Because the text "This is a passive ability; it does not need to be activated." is used within the processing for this opcode.
Reply With Quote
  #7  
Old 10-05-2009, 01:47 AM
KLS
Administrator
 
Join Date: Sep 2006
Posts: 1,348
Default

I doubt the server would need to know anything about the internal data pointers of the client outside of simple offsets(wouldn't be the first packet to work like this). It's probably holding a set of data in memory from a previous operation and using it to parse that packet.
Reply With Quote
  #8  
Old 10-05-2009, 01:57 AM
Pend
Fire Beetle
 
Join Date: Sep 2009
Posts: 16
Default

Indeed, as was the case for the other ones (ie. you couldn't get an object ptr for OP_ShroudSelEquipDetail without having first opened the window via OP_ShroudSelectionWindow). There's a sub that's specific to these opcodes and I've exhausted them hunting for the one that enables this one. I think I'll need to dig into some of the higher level unhandled opcodes. Just in a few minutes, I found quite a few that weren't referenced in patch_Titanium.conf, so I can go through those, I guess:

#0x11cd .text:00404D2A
#0xd743 .text.004515DA
#0x79b4 .text.00461682
#0x7c59 .text.00461671
#0x7abc .text.0046168E
#0x7c12 .text.0046169A
#0x7c32 .text.004616A6
#0x6966 .text.004611AC
#0x6A00 .text.004611B5
#0x6C97 .text.004611BD
Reply With Quote
  #9  
Old 09-11-2014, 03:04 AM
Tyen05
Discordant
 
Join Date: Mar 2009
Location: eqbrowser.com
Posts: 309
Default

bumping this, because it's an A+ thread
__________________
Browser based EQ project
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 07:36 PM.


 

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