Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

[v62/v83] [For WZ Edits] Hair/Item Cap Client Fix

Initiate Mage
Joined
Apr 6, 2017
Messages
33
Reaction score
0
By popular demand I decided to go back and look into the client to see where to remove the very common Item and Hair client caps. For anyone that doesn't already know, in low-version clients (such as 62), the maximum ItemID that will be recognized for items is is something that has a ID less than 3000 (e.g 1003000 for hats won't work in 62). There is also the common Hair cap where your character's hair becomes bald if the HairID is >= 40000.

Starting off with the Item Cap in lower version clients -- why does it happen? Well, Nexon has three genders used for items and this is how they are identified: 0 for Males, 1 for Females, and 2 for None. So with these three genders and how Nexon's items work (using hats again for example), 1000000 is a Male-only item, 1001000 is a Female-only item, and 1002000 is a item for all genders. Let's see the math behind this.

PHP:
if ( nItemID / 1000000 == 1 )
    nItemGender = nItemID / 1000 % 10;
  else
    nItemGender = 2;
  if ( nGender != 2 && nItemGender != 2 && nGender != nItemGender )
    return 0;

So first off, this Gender check is only in place for equipment (ID's that start with 1). The gender is formed from nItemID / 1000 % 10. So, 1000000 / 1000 % 10 = 0 (Male), 1001000 / 1000 % 10 = 1 (Female), and 1002000 / 1000 % 10 = 2 (None). This makes sense, so what about items that are 3, like 1003000+? Well, 1003000 / 1000 % 10 = 3.. It's not 0, 1, or 2. So the only way to wear an item over 1003000 is if you made your character's gender a 3 so that the character's gender is equal to the same gender of the item.

So how can we fix this? Well, we can easily just change the assembly instruction in the client from checking if the Gender is NOT 2 and the Item's Gender is NOT 2, and instead change it so if the Gender is LESS than 2 or if the Item's Gender is LESS than 2 (either 0 or 1 -- Male or Female), THEN we can validate if the character's gender and the item's gender are equal or not.

This is a extremely easy fix! We just need to change two simple instructions from JE to JL (you can do this in OllyDbg). For v62, here is what you have to modify (ignore the comments, they're just to better explain):
Code:
Change:
0044D7D4    je      short 0044D7DF ; if (nItemGender != 2)
0044DA9A    je      short 0044DAA5 ; if (nItemGender != 2)

To:
0044D7D4    jge     short 0044D7DF ; if (nItemGender < 2)
0044DA9A    jge     short 0044DAA5 ; if (nItemGender < 2)

Change:
004C2221    cmp     edx, 2
004C2224    je      short 004C2235

To:
004C2221    cmp     edx, 1
004C2224    jg      short 004C2235

Next up is the Hair Cap. A lot of people seem to need this fixed, especially now that the new clients actually have hairs that are over 40000. The issue here is the same issue as above with the math and the conditions expected. When the client registers your Local User, it processes your item's actions and merges the sprite into the Sprite Animator which the WZ will then calculate each position specific to your character's current action which will result in Drawing your character on the screen. When you load all of the item's actions, the client has to parse each ID on your character and then find the assets within your game files. It determines the directories based on the unique type of Item (as Nexon refers to "Type Index" -> ItemID / 10000). The reason why hairs can't go over 39999 is because the directory path for Hair is only located for Hairs if the HairID / 10000 == 3 (meaning no matter what, the first digit is always a 3). In newer clients, Nexon made this into a big switch statement including case 3: case 4: for the hairs. I'm not really sure which version this was initially changed since the v95 PDB still uses a 30k hair cap.

Here's a quick glimpse at the check:
PHP:
if ( v2 == 3 )
{
  v8 = StringPool::GetStringW(&v42, 2300);
  LOBYTE(v45) = 4;
  sub_419192(v8);
  LOBYTE(v45) = 1;
  v5 = &v42;
  goto LABEL_17;
}

The fix? Just as simple as the one above, change two instructions! Now, while v83 has the Item Cap fixed, Hairs will continue to remain a problem for quite a long time, which is why I include the addresses for this version in addition to 62.

v62 Addresses:
Code:
Change:
0054E321    cmp     eax, 3
0054E324    je      0054E3F8 ; if (nID / 10000 == 3)

To:
0054E321    cmp     eax, 4
0054E324    jle     0054E3F8 ; if (nID / 10000 <= 4)

v83 Addresses:
Code:
Change:
005C94FC    cmp     eax, 3
005C94FF    je      005C958D ; if (nID / 10000 != 3)

To:
005C94FC    cmp     eax, 4
005C94FF    jle     005C958D ; if (nID / 10000 > 4)

NOTE: If for whatever reason you wanted Hairs to later cap at 50000 and not 40000, just change that "4" to a "5" and your client will then render hairs up to 59999.

Hope this helps all the low-version WZ Edit servers!

- Eric
can i know where should i change these?
 
Initiate Mage
Joined
Apr 6, 2017
Messages
33
Reaction score
0
Your localhost (client) using OllyDBG.

ooh thanks alot! i changed them, now i can see the hairs but not the face any idea what happen? ._. ( the face became blank )

ahh, some hair also bald xD

- i tried to import v14x hair to v83
 
Joined
Jan 18, 2010
Messages
3,109
Reaction score
1,139
thanks, umm however if i were to edit for v117.2 item cap where/ which address should i look for?

post-bb paths were a little more advanced iirc. from the clients i've looked into starting from v92 and up, they moved from conditions to a switch-table. you need to modify the index of the switch table's jump location to jump to the return value of hairs when it's nTI type 4 (itemID / 10000). you need to find the function get_equip_data_path which you can do by using StringPools.
 
Initiate Mage
Joined
Apr 6, 2017
Messages
33
Reaction score
0
post-bb paths were a little more advanced iirc. from the clients i've looked into starting from v92 and up, they moved from conditions to a switch-table. you need to modify the index of the switch table's jump location to jump to the return value of hairs when it's nTI type 4 (itemID / 10000). you need to find the function get_equip_data_path which you can do by using StringPools.

i dont really quite understand,
however where and how should i modify the index of switch table, and also ' get_equip_data_path '
sorry yea, im quite noob at these stuff. still learning .__.
 
Junior Spellweaver
Joined
Jan 10, 2017
Messages
105
Reaction score
6
How can I save what I have changed?
 
Last edited:
Experienced Elementalist
Joined
Sep 27, 2016
Messages
217
Reaction score
68
00AF5299 cmp eax,0
00AF529C sete cl

something like that right? not sure since I did this long ago
 
Initiate Mage
Joined
Dec 17, 2009
Messages
5
Reaction score
0
After searching I found the addresses you mentioned, when I changed them I tried running my client and it still DC'ed me when I scrolled through the hairstyles/faces. Any idea what's up? (V83)
 
Initiate Mage
Joined
Sep 27, 2018
Messages
91
Reaction score
20
After searching I found the addresses you mentioned, when I changed them I tried running my client and it still DC'ed me when I scrolled through the hairstyles/faces. Any idea what's up? (V83)

Not a client issue, you didn't import them to the WZs correctly. If you had imported them correctly and didn't apply the client fix... your character would be bald, not cause a DC.
 
Initiate Mage
Joined
Dec 17, 2009
Messages
5
Reaction score
0
Thanks. I’ll go dump the wz again when I’m home and I’ll let you know.
 
Joined
Jan 18, 2010
Messages
3,109
Reaction score
1,139
Not a client issue, you didn't import them to the WZs correctly. If you had imported them correctly and didn't apply the client fix... your character would be bald, not cause a DC.

Actually it's a client issue I overlooked. As Umbreon pointed out previously, Nexon has two additional checks for hairs on top of being able to render them when it comes to using hairstyle NPC dialogues. If the first hair isn't a valid hair range, or you scroll to invalid hair, you'll dc just the same. Check out his post here to the explanation behind that problem.
 
Initiate Mage
Joined
Sep 27, 2018
Messages
91
Reaction score
20
Are you sure? It didn't crash my client when viewing them via style npcs, they just rendered bald there too.

Edit:
Oh yeah, if you're using HeavenMS, you have to change the hair ID range in the source too. That's probably causing your disconnection since the source would think you're packet editing. lol
 
Initiate Mage
Joined
May 14, 2019
Messages
51
Reaction score
0
thank you so much.
i can see the new hair with use command: !hair 40000
but it still will be crash when add hair 40000 to the npc script, :(
 
Initiate Mage
Joined
Jul 5, 2017
Messages
12
Reaction score
1
Who ever uses "HeavenMS" Source Can do it without Client edit at all.. Just need to Add the ID's Ranges to: MapleItemInformationProvider.javaJust change the the Highest ID here to the Highest ID in you .WZ Files And you got it fixed without client editing theData = eqpStringData; cat = "Eqp/Accessory"; } else if (itemId >= 1000000 && itemId < 1010000) { theData = eqpStringData; cat = "Eqp/Cap"; } else if (itemId >= 1102000 && itemId < 1103231) { theData = eqpStringData; cat = "Eqp/Cape"; } else if (itemId >= 1040000 && itemId < 1050000) { theData = eqpStringData; cat = "Eqp/Coat"; } else if (itemId >= 20000 && itemId < 28846) { theData = eqpStringData; cat = "Eqp/Face"; } else if (itemId >= 1080000 && itemId < 1090000) { theData = eqpStringData; cat = "Eqp/Glove"; } else if (itemId >= 30000 && itemId < 48107) { theData = eqpStringData; cat = "Eqp/Hair"; } else if (itemId >= 1050000 && itemId < 1060000) { theData = eqpStringData; cat = "Eqp/Longcoat"; } else if (itemId >= 1060000 && itemId < 1070000) { theData = eqpStringData; cat = "Eqp/Pants"; } else if (itemId >= 1802000 && itemId < 1842000) { theData = eqpStringData; cat = "Eqp/PetEquip"; } else if (itemId >= 1112000 && itemId < 1120000) { theData = eqpStringData; cat = "Eqp/Ring"; } else if (itemId >= 1092000 && itemId < 1100000) { theData = eqpStringData; cat = "Eqp/Shield"; } else if (itemId >= 1070000 && itemId < 1080000) { theData = eqpStringData; cat = "Eqp/Shoes"; } else if (itemId >= 1900000 && itemId < 2000000) { theData = eqpStringData; cat = "Eqp/Taming"; } else if (itemId >= 1300000 && itemId < 1800000) { theData = eqpStringData; cat = "Eqp/Weapon"; } else if (itemId >= 4000000 && itemId < 5000000) { theData = etcStringData; cat = "Etc"; } else if (itemId >= 3000000 && itemId < 4000000) {
 
Back
Top