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!

Updating a Server from One Version to Another [Updated]

Joined
Jun 5, 2010
Messages
567
Reaction score
598
Disclaimer: If you don't want to read a wall of text, then this guide is not for you. If you are too lazy to read this, you do not have the patience to update and therefore really shouldn't be updating in the first place and I did not write this guide for you.

General Introduction:
Updating takes time and general knowledge of the game. Some creativity might be involved as well. A few basic things must be known beforehand if anyone is interested in updating. These are the very basic definitions and without this, it is quite useless to proceed any further. I will give you an efficient way to packet sniff and update with possibly a few tricks to save time, but it is still up to you to learn the logic behind updating. I am also assuming this is updating for OdinMS source but the same concepts can be applied for Vana and DelphiMS. I haven't ever looked at Titan or the C# sources so I cannot say the same, but packets are the same for the game. I will also use v88 and v147 as I am most familiar with v88 and MapleGlobal was at v147.2 at the time the guide was written. Still, if you want to update MSEA to the latest version, this guide will still work. I will also make sure the guide works for both odinms sources using properties files and those that do not.

Why Learn Packets?

If you actually want to run a successful server with no competition, updating to the latest version is important. Now you ask me why I haven't done this for MoongraMS (according to Flav, I "don't know how to"). I simply don't have the time and energy for this stuff anymore as even though I have done it before, I have no motivation or time to do it anymore. If you're going to "aim for #1 " you're going to have to keep up with the competition that is going on. True, custom features and the site are "almost as important" as the game itself, but this is the easiest way to get players quickly and not being labeled as a terrible server who is only top because of insane rates.

Definitions and Basic Information:
-Byte: 1 byte
-Short: 2 bytes
-Int: 4 bytes
-Long: 8 bytes
-This will be done in hexadecimal so it is base 16. It is useful to have calculators for hex to decimal (dec) and dec to hex at the ready. It is also useful to know some basics such as 0xA in hex = 10 in decimal, 0xB = 11, and possible some multiples of 16. It is useful to also know how to multiply and add in your head. Since I can do that, for all bytes I can calculate the values pretty fast by doing it in my head. To differentiate between a value that is hexadecimal and decimal, all hex values start with 0x.
-The packets on Maplestory are in little endian format, which means the once converted to hexadecimal (hex), they are reversed. This means that if something was 0x12345678, once converted to little endian, it would be 78 56 34 12. Using the same principle, a group of 4 bytes that are 00 30 20 10 will be 0x10203000 in hex form.
-Packets are sent between the server and client to transfer data and information. The GUI is a projection of it, in a way.
-Actions that are handled by packets on Maplestory are defined by a short (2 bytes) in the beginning of the packet. Some actions may share the same short. We will call this short an opcode. Both packets sent and received by the server have opcodes. Naming these opcodes will help a lot.
-Handlers are for receive packets (received by the server FROM the client). MaplePacketCreator is for send packets (in Lithium sources it's CWvsContext, CField, etc). By receiving packets, I mean that the server receives the packets and not the client. Similarly by sending packets, I mean the server sends the packets.

Other Misc Information:
-Levels, small details like pvp rank are bytes
-Jobs, stats, item slots, personality traits (charm, ambition) are shorts
-Map ID, NX cash amounts, Azwan Honor are ints. HP and MP are also now ints.
-Mesos, exp, map id are now longs
-Buffstats are ALSO ints

Updating Opcodes:

Introduction
Updating opcodes is the first step to updating a version from one to another. This step takes either a lot of time, or a bit of time and some logic.

It is important to know about common things Nexon does with their opcodes. The most important thing is to know that Nexon usually keeps the opcodes between versions in order. This is not always true as some opcodes are moved around in some versions, but for the most part, most of the opcodes stay in order. Knowledge of what is added and removed is somewhat important as well. For example in v88 there were monster books, but by big bang patch they were removed. It is possible that the opcodes were removed as well, causing the values of the opcodes to go down.

How to Work a Packet Sniffer:
After knowing this, it is time to go and grab some packets from the game. I personally favor SnowSniffer solely due to the ASCII printout, but I currently use MapleShark and will be writing a guide about it. It is googleable and just look for the latest version, which I believe is 2020. If you don't have .NET framework, get that as MapleShark needs it. Download and install while you're at it since this is needed for packet sniffing.

I have gotten some questions on MapleShark not working for a few people, so I will also include a small guide. Open up the executable and set the settings. If you are on wireless, choose wireless. If you are on ethernet, use local area connection when it asks for it. Sometimes you have to pick option number 2 of these sections.

SuperLol - Updating a Server from One Version to Another [Updated] - RaGEZONE Forums

MapleShark also asks you for the ports you want to sniff. Set those from 8500-8700 (channels start at 8585, login is 8484, cash is 8686 so adjust accordingly). The ports don't quite reach 8700, but use 8700 for simplicity. When you have this open, you can change channels or log into the game and packets will start being logged. If packets are not logged right away, then switch up the settings and try again.

How to Packet Sniff Efficiently:
Good packet sniffing isn't just mindless moving around and training on monsters, contrary to popular belief due to released packets during v80 days. No, those packets are pretty useless and so are the people thanking them. The problem with those packets is that there will be an abundance of movement packets, monster packets, and attack packets, which you don't need more than a few of to update. When you packet sniff, you need to get what you want, quickly and clearly. To packet sniff efficiently, do one function at a time. Look through the receive packets and send packets and find the ones you want to sniff. An easy approach is to say what you want to sniff before sniffing the exact action. For example if you want to sniff meso drop, don't just drop mesos and move on, say DROPPING MESOS and then drop mesos. Also know how many mesos you dropped. Saying something like DROPPING 256 MESOS is better than saying DROPPING MESOS. It is important to do exactly what you said before, to make it easy on yourself (drop 256 mesos if you said you would). After sniffing one feature that you wanted to sniff, say in chat that you are done. This will be useful later on when you look at your log. You will know the general area of what you just sniffed by looking at the packet log. Once you have a sizeable log with many things sniffed, you can stop sniffing. If this is your first time updating and you have little experience, then sniff a bunch of things so you can fill in the unknown opcodes later on.

An easier example for sniffing:
Wanted: Creating a party
Before you create the party in game, say in all chat: CREATE PARTY
Then quickly create the party before doing anything else
Right after you create the party, say in all chat again: FINISHED CREATING PARTY
After that, go to MapleShark, find where in the log you said CREATE PARTY, and between the places where you said CREATE PARTY and FINISHED CREATING PARTY will be the create party packet (explained in next section).

Analyzing Packet Logs and Updating First Opcode:
Now that you have packet logs, log off of MapleStory. You don't want more packets coming. Now go back to the MapleShark GUI and scroll down each packet that is logged. The packets received by the server will be outbound, and the packets sent by the server will be inbound. The names are counter-intuitive but if you think about it the other way around by replacing server with client, then it would make sense (receive by client = inbound). The opcode is given at the side as well along with the packet length. This will be useful later on. Now it is the time to find when you talked. Scroll down each packet until you find where you talked. The textbox to the bottom right of MapleShark gives you an ASCII printout.
SuperLol - Updating a Server from One Version to Another [Updated] - RaGEZONE Forums


To find out the sections you have just sniffed, start with what you first sniffed and scroll down to what you just said in plain text. In the previous section I suggested dropping mesos or creating party to be the first one to sniff. If you used that example, then search for a packet that has text that says DROPPING MESOS or CREATE PARTY. This is generally the first step to analyzing packets: Knowing where your packets you sniffed are. The next step would be knowing where your sniffed section ends. For that, it is easy as well, and scroll down until you see text that says FINISHED CREATING PARTY or something of that sort. It should be at most a few packets below. If it isn't, then there could be something wrong, or you enabled too many packets to be sniffed.

Now that you know the general area, look at the first packet that had the text. If it is outbound, then that packet will be for receive packets. Get the opcode that MapleShark says it is. The packet that has the plaintext is the chat packet. In v88 it is 0x31. In v99 it is 0x37 and in v112.4 it is 0x59. In v147.2, it is 0x6A. Navigate to the file where the receive packets are stored. Get the old value of GENERAL_CHAT and change that to the new value. Example: v88 is 0x31, v99 = 0x37, v112.4 it = 0x59. Change 0x31 to 0x37, or 0x59 for v112.4, or 0x6A for v147.2. Since 0x59-0x31 = 0x28 = 40, note that it is +40. This will come in handy later. If you are experienced or very good at mental math, you may skip this step. You have updated your first opcode. Next go back to MapleShark and look at the inbound packet containing the words you have said. This is also GENERAL_CHAT, but in send opcodes. Go to where your opcodes are stored and change that for CHATTEXT as well. In v88 it is 0xA2. In v99 it is 0xAF. In v112.4 it is 0xF8. Just as a freebie, the send opcode (incoming) for CHATTEXT is 0x169 in v147.2.

Opcode Naming:
Now you may be thinking, how did I know it was CHATTEXT and GENERAL_CHAT for send and receive packets respectively? Perhaps you may be thinking, how would you know what the packet names are right off the bat? There is no simple answer to this. I just know because I've done this many times. Although the packets are not badly named, some are a bit confusing. For example, in my source I have ARAN_COMBO for receive packet but the handler is named DamageMonsterHandler for some stupid reason. Oftentimes figuring out this for the first time may take a while. Here are some helpful tips though: Remember that packet opcodes stay in order for the most part. In v88, ARAN_COMBO comes before CS_OPERATION (doing things with cash shop). If you got something like ARAN_COMBO and it is 0x9999, then it is way too high since it's greater than the value of cash shop (when you sniff that later on) and you're probably doing it wrong. However, if you got something like ARAN_COMBO being 0xBA, then it may be reasonable. There are many ways to verify if it is correct and this will be gone more in depth in the Looking At Packet Structures section of this guide.

To name an opcode, right click the naming section of the packet line. Then enter the name in regularly. Make sure the name you give the opcode is relevant to the opcode. Otherwise confusion will occur.
SuperLol - Updating a Server from One Version to Another [Updated] - RaGEZONE Forums

Analyzing Packet Logs Continued:
So you have just found the GENERAL_CHAT opcode. This is a very important step. To make things easier for yourself, at any GENERAL_CHAT packet, right click it and name it GENERAL_CHAT (RECV). The good thing about MapleShark is that it can search for the packets you have logged based on opcode. No one wants to read through a list of hexadecimal numbers like Outbound 0x37, so naming it something in English will help. After this is done, scroll down to the next few packets. Remember we only updated chatting, and we have not even updated what we were trying to update, which is the function of what you said. While doing updates, I sometimes drop mesos first. Now it's time to use your brain. Find the old opcode for dropping mesos. Start in the Recv handler. Now the question is how did I know it was receive? There are two reasons. One, experience, and I know that it is receive, and it sends a DROP_ITEM_FROM_MAPOBJECT packet. Secondly, think back and remember those exploits on GMS about duping mesos. Also think about the meso hacks back in the older versions through packet editing negative values. Packet editing is done completely in receive handlers since clients send a custom packet that will be received by the server. Anyways now that you have the packet opcode from the old version, remember that most of the time opcodes go up, but not at a crazy rate. In v88, it was 0x5E. Now search for packets that around around that area and outbound. If you need more help, look at the mesodrophandler, and figure out what the packet length should be around (more indepth in analyzing packet structures). Since this is not covered yet, you will not know the exact length from v88, but think about it. Does a lot of data need to be transmitted for dropping mesos? Probably not. The meso count is needed, possibly what dropped it matters, and possibly when it dropped matters, and even perhaps the location of the drop. This means the packet will not be insanely long. So look around for a short packet.

When you find a decent sized packet around the old opcode, time to check if it is correct. This is where remembering how much you dropped comes in. Drag your mouse and highlight 4 consecutive bytes in the packet. You may highlight it in the bottom of the GUI and the integer provided will be calcuated into decimal on the righthand side of the GUI. If that doesn't match the amount of mesos you dropped, keep going. Keep going until the end and if none of the ints match the amount of mesos you dropped, you have the wrong packet. The question is now how is it an int. There are again 2 ways I know it's an int. One, through experience and the second through looking at the packet handler (more info to come). Anyways after a few trials, the meso drop opcode should be found to be 0x69 for v99 (0xA8 for v112.4). Replace the old one with this one. The old opcode was 0x5E, and 0x69-0x5E = 11 so add a +11 tag next to it (for v112.4 there's a crazy jump from v88). Now it's time to check the send packet. Because you know the receive opcode is MESO_DROP, find the handler that corresponds to it.

Update: For V112.4 it is: 0xA8 for MESO_DROP (RECV). 0x1D3 for DROP_ITEM_FROM_MAP_OBJECT (SEND)

Obviously it is MesoDropHandler, but if the opcode was named badly, there must be another way to find the handler. The foolproof way to do it is through searching an IDE. I will assume Netbeans here, but those that use Eclipse have a very similar feature. Right click the variable called MESO_DROP and select the option find usages. In Eclipse it is similar. Select the default choice and it will find you the usages of the variable. Double click the line of code that uses it. This will take you to PacketProcessor.java (in odinms) and next to the line of the code will be the name of the file. Press ctrl, and then click on the name of the file. This will take you straight to the file (IDE Shortcuts!). In the handler, sometimes there will be a c.getSession().write(MaplePacketCreator.stuff); line of code. This tells the server what packet to send back to the player. In some handlers, more than one of these will be used and in others, there will not be an packets sent at all. This is where code reading needs to take place. Remember what you did and navigate to the correct section of code. Find the packet that the server sends (if any) and go to that method (hold down the control key and click on the method). The method will be something like public static MaplePacket blah() {MaplePacketLittleEndianWriter mplew = stuff; mplew.writeShort(<OPCODE HERE>);/*code omitted*/}. Find the opcode in <OPCODE HERE>. In the case of meso dropping, it would be DROP_ITEM_FROM_MAPOBJECT. Go back to where the send opcodes are located and get the old opcode for DROP_ITEM_FROM_MAPOBJECT.

Now go back to MapleShark and find the packet sent after MESO_DROP. If the packet opcode is reasonably near the old one, this may be the correct packet (to be verified later on). For now replace the old opcode (v88 = 0x10C, v112.4 = 0x1D3) with the new one you have found. Calculate the difference and make note of it for future checking. This whole procedure needs to be continued for everything you have sniffed. If you are too lazy but this is your first time doing this, then stop right now. It is not worth continuing as this is one of the easier parts and the part that really takes the least amount of work. Updating is not for the weak.

A general idea of checking packets.
SuperLol - Updating a Server from One Version to Another [Updated] - RaGEZONE Forums

SuperLol - Updating a Server from One Version to Another [Updated] - RaGEZONE Forums

SuperLol - Updating a Server from One Version to Another [Updated] - RaGEZONE Forums

Guessing Opcodes (theoretical examples):
Now after a good size of opcodes are updated in this tedious manner, a few other tricks can be utilized. Possibly the most useful one is guessing opcodes with good accuracy. This is where the adding the packet increases and decreases such as +11 for meso dropping.
I have prepared an example in v147.2 to show what I mean (these are actual opcodes!):
You current source version is v117.2 and you want to update to v147.2
Your opcodes are as follows (for RECV):
MOVE_FAMILIAR = 0x14D
TOUCH_FAMILIAR = 0x14E
ATTACK_FAMILIAR = 0x14F
REVEAL_FAMILIAR = 0x151
QUICK_SLOT= 0x152, 0x1E1

You log on GMS and sniff that MOVE_FAMILIAR is 0x1DC by getting your familiar to move around and logging packets. You also log on and get quick slot packets to be 0x1E1 by changing your quick slots and getting the packets for it. However, you don't have any monsters to attack but you want to know the value of the ATTACK_FAMILIAR packet and you have NO IDEA what REVEAL_FAMILIAR is. The good thing is with this method, you can still figure out what the packet opcodes are.

MOVE_FAMLIAR was 0x14D and went to 0x1DC so it had a +143 jump.
QUICK_SLOT was 0x152 and went to 0x1E1 so it also had a +143 jump.
From this, we can just assume that everything in between also has a +143 jump. You can never be 100% sure, but as mentioned before Nexon likes keeping packets in order, so you can make this assumption with high accuracy. Using this logic, TOUCH_FAMILIAR is 0x1DD, ATTACK_FAMILIAR is 0x1DE, and REVEAL_FAMILIAR is left as an exercise to the reader.

Additional Tips:
Because of the guessing strategy, opcodes can easily be filled up pretty fast. There are a few ways to make your life easier. Firstly, don't sniff everything in the same area. True, you may get completely perfect opcodes in that section, but usually you can guess those. Spread the packet sniffing throughout the opcodes list. Maybe sniff MESO_DROP, then sniff going into cash shop, then sniff some familiar info, go sniff some attacks. Use the knowledge of packet guessing to your advantage.

Sometimes guessing with certainty isn't purely enough and you get something like
ACTION_1 = 0x55 //+4, was 0x51
ACTION_2 = ? // was 0x52
ACTION_3 = 0x65 //+5 was 0x60

For these examples, look at what the actions are. If action_1 is scrolling, and action_2 is like enhancement scrolling, and action_3 is something to do with moving items, then it is more likely for the ACTION_2 to get the +4 than the +5. Another way to know this is that 0x52 is closer to 0x51 (looking at old values).

Knowing what packets represent and when they are used what is also good to remember. Some of the packets are actually badly named in OdinMS. For example, DROP_ITEM_FROM_MAP_OBJECT is also used when you enter a map. A name like SPAWN_ITEM would probably be more accurate. WARP_TO_MAP is used when you log in but also at other times. PARTY_CHAT (RECV) in some sources should more properly be named something like MULTICHAT since alliance, buddy, and guild chat all use the same handler. Of course the actual names in the client are better, but this guide does not cover that far (you will not be able to look in the client yet).

Summary for Opcodes:
1. Sniff the easy opcodes but with efficiency and clarity.
2. Update the easy opcodes, go from RECV to SEND if you are not experienced although this doesn't really matter
3. Guess the opcodes that you can guess with high certainty.
4. Go back and sniff the ones that are missing and repeat #2-3 until a good list is done for send and receive packets.

Part 2 for reading packet structures and part 3 for updating packet structures coming soon.
 
Last edited:
Joined
Jun 5, 2010
Messages
567
Reaction score
598
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

Reading and Updating Packet Structures

Introduction:

So now that you have a good list of correct opcodes, sniffing packets should be no problem at all (especially with snow sniffer, and MapleShark if you name your packets like I do). Now it's the time to update packet structures that are incorrect. Before updating packet structures, you must know how to read the packets and how to make sense of them.

Requirements:

-Basic Java knowledge (including for/while, arrays, and basic data structures)
-Reading the above
-Knowing how to follow directions

Starting out:

Just as a reminder, a byte = 1 byte, a short = 2 bytes, an int = 4 bytes, and a long = 8 bytes. A few of the common variables that take on these data types are listed above (i.e. job id is saved as a short). A byte is the pair of hexadecimal digits. Of course it has a deeper definition, but this is all you really have to know. In a packet 13 00 00 00 00 00 00, each pair would be a byte. Also, hexadecimal notation is 0x followed by a number 0-9 or a letter A-F. Having the 0x symbolizes that it's hexadecimal.

Checking packets for Outbound:
Now we take a packet, and check if it is correct. If you cannot log into the game, this is the only way to update packets as you have no clear way of testing. Let's take the packet that is sent when you move into the cash shop. The packet in v99 is 13 00 00 00 00 00 00. From working with opcodes, you should have an idea of what packet this is in MaplePacketCreator (enableCSUse0 or something, depending on source). Now the job is to check if it works correctly.

Writing/Reading packets have methods in the source. To add a byte to a packet (send), use write, to read (receive), use read. write(number) will write a byte, writeShort(number) will write a short, and writeInt(number) will write an int. The same principles can be applied to the other ones. However, there are a few special methods. One of the most important ones to understand is readMapleAsciiString and writeMapleAsciiString, which will be explained later as it's slightly more advanced.

So let's go analyze a packet. First we need to combine the opcode with the packet itself since MapleShark gives opcode, and then the rest of the packet separate. The opcode of the packet we will be looking at is 0x00FA = FA 00 (outbound). The packet is 2A 00 00 00 52 00 00 00 47 00 00 00 49 00 00 00 1D 00 00 00 53 00 00 00 4F 00 00 00 51 00 00 00. Combined this will be Outbound FA 00 2A 00 00 00 52 00 00 00 47 00 00 00 49 00 00 00 1D 00 00 00 53 00 00 00 4F 00 00 00 51 00 00 00.

This packet is for quickslots (in v99) but in case this is not obvious, take the first 2 bytes and find the opcode referring to that. It is in little endian form so when you put the short together, you have to reverse the bytes, so the opcode will be 0x00FA. Browse through your receive opcodes and find the receive opcode corresponding to the value, which in this case is 0xFA. Find the handler that corresponds to that opcode and open it up.

Reading and checking a packet requires working from the beginning and going forward. This is little point of starting in the middle unless more experience is gained (tips will be shown later). Anyways, the thing about a outbound packet is that in the source, there is always a short read in the beginning no matter what. This is to identify which handler it should go to. So we can start reading the packet now that we know the structure, at least in the old version. We start with slea.readShort(); to get the handler it calls. The first two bytes are FA 00, and since it's a short it would be 0x00FA. The important thing to remember is the following few steps.

One, after you read them, the bytes won't be looked at during further reading. Because of this, it is useful to keep track of where the packets are, and if it is a byte, short, or any other. So we have read FA 00, so we can put brackets around it to symbolize it is a short. So far, a short has been read and it is looking like [FA 00] 2A 00 00 00 52 00 00 00 47 00 00 00 49 00 00 00 1D 00 00 00 53 00 00 00 4F 00 00 00 51 00 00 00. The second thing to think about while reading through the packets is to make sure the packet values make sense. You cannot go wrong with the packet header (or opcode, or just first two bytes), so you do not need to worry about it here, but in the future this is vital.

Next, look in your handler and you should see something like for (int i = 0; i < 8; i++) {int key = slea.readInt(); /*omitted code*/}. This basically says readInt() 8 times. So we go through the packet again, going through ints each time. An int, as stated before is 4 bytes. The first one will be 2A 00 00 00. As this is little endian, again, the bytes are reversed before being put together. So when it is read, it will be 0x0000002A. Add brackets around the 2A 00 00 00 indicating that it is finished. The packet should now look like [FA 00] [2A 00 00 00] 52 00 00 00 47 00 00 00 49 00 00 00 1D 00 00 00 53 00 00 00 4F 00 00 00 51 00 00 00. The next step would to be making sure the part that was just read made any sense. Is it reasonable to have a key have a value of 42? It seems possible so move onto the next int. Repeating the above will eventually take you to
completing the packet with [FA 00] [2A 00 00 00] [52 00 00 00] [47 00 00 00] [49 00 00 00] [1D 00 00 00] [53 00 00 00] [4F 00 00 00] [51 00 00 00].
Because all the ints make sense, this packet doesn't seem to need updating so we are done here.

Incorrect Packets for Outbound:
Unfortunately having correct packets from one version to another is not always the case. A perfect example is here in this receive packet (opcode already included): 73 00 5F 98 95 02 02 00 00 00 00 02 00 00 00 00 00 00 31 00 00 00 00 01 00 00 00 00 00 00 AB 00 00 00 which was for auto assign for the jump start level 50 Evan. The first step is to once again identify the opcode. The opcode is the first two bytes, reversed so the opcode would be 0x0073. If you have followed the updating opcodes part of the guide and have completed it, this will be found to be AUTO_ASSIGN. Find the handler that uses AUTO_ASSIGN and enter it. We have already analyzed the first 2 bytes so we can skip that already. We go through the first packet reading and see if it makes sense. slea.readInt(); (or slea.skip(4) which basically means read 4 bytes) is the first thing that is read after the header. It is also said to be the timestamp. Again, we have to reverse the bytes when we read it and it is an int so we read 4 bytes. We should get 0x0295985F. Use MapleShark's calculator or a hex to dec calculator to see if this makes sense. It should as timestamp is usually high. Because it makes sense we can move on. So far we have [73 00] [5F 98 95 02] 02 00 00 00 00 02 00 00 00 00 00 00 31 00 00 00 00 01 00 00 00 00 00 00 AB 00 00 00. The next line says slea.readInt(); which is the count of stats updated with auto assign as a comment or the variable name should say. Go through the next 4 bytes as usual and you'll get that the value is 2. Updating 2 stats makes sense so we can go passed this.

Now we have [73 00] [5F 98 95 02] [02 00 00 00] 00 02 00 00 00 00 00 00 31 00 00 00 00 01 00 00 00 00 00 00 AB 00 00 00. The loop iterates 2 times, because of the 2 previously, so we go to the next line and it says which stat it updates and that it is an int. The int read is 00 02 00 00 and as that is in little endian, we change it to hex form and it'll be 0x200 (512) = updating luck according to the if statement if (type == 512). This makes sense so we can move on. The next int according to the handler says that the next int would be the amount gained. The next int read is 00 00 00 00. It seems kind of strange that the gained amount is 0, but this is not impossible so we can move on. Had it been more than 1000, then it would have been weird. This is where knowledge of the game comes in though. Auto-assign gives you regular stat build and since this was a stripped level 50 Evan, this should have given some luck.

Next, we reenter the loop due to it being looped twice. Again, it asks for the stat that will be updated. This time it is 31 00 00 00, which is 49. This doesn't make sense though, as there isn't a stat that is 49. There are a mixture of stats that can reach 49, but not a single stat. Something is clearly wrong and doesn't make sense. This is when we notice there is a structure problem. What to do now is to think about what the 49 could be. I said above that the character was a jumpstart Evan which was level 50. Remember that before the luck gain was 0. Would 49 likely be a better luck gain? I had 4 in luck already and luck = 3 + your level for Evans at level 50. Would this be correct? The answer is yes, the 49 would probably be the luck gain. This means that there is a new int between the stat and the stat gain. What you can do now is to add a slea.readInt() after the int type = slea.readInt(); to indicate that it is new. Check the rest of the packet until you reach the end. The newly added int should fix the packet. You have now updated a packet from one version to another.

Additional Words and "Error" Correction:
Note that I knew that it should have given some luck because it was my character so I would have noticed something wrong right away. If it wasn't my character, there would be no easy way to tell if I had the required luck to begin with and would move onto the next line like above. This is another reason why getting other people to post packets they sniffed is not always good. You know your character, but you don't know anyone else's. Also, that "int" that was added is actually a long which was added for all stats. Because of the traits system, the int became a long, but this was not mentioned here as this would be confusing. Auto assign doesn't affect the traits and personality system so it doesn't really matter.

Checking Packets for Inbound - Starting Out:
The concept is the same, and you still trace over the packet as before. However, instead of finding the opcode and skipping over the first 2 bytes to enter a handler, this is not done here. If we want to check a packet like 13 00 00 00 00 00 00, which is the packet apparently to enable a few actions, we would start with checking 13 00. Before we do this, we have to understand what the packet being created in MaplePacketCreator is trying to do. Another difference is instead of reading bytes, we would write bytes instead.

public static MaplePacket enableCS0() {
MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();
mplew.writeShort(0x13); // or SendPacketOpcode.ENABLE_CS_0 or SendPacketOpcode.ENABLE_CS_0.getValue();
mplew.write0(5); // or mplew.writeInt();mplew.write(0);
return mplew.getPacket();
}

The first line is the method definition. It is a public method so it is accessible everywhere. It is static so it's a class method and not called by an object. It returns a MaplePacket. The second line creates an object of type MaplePacketLittleEndianWriter. This is what we "write" our bytes into to make it simple. The next line, we write a short that is 0x13. This means we add 13 00 to the empty packet from line 2. Next we do mplew.write0(5); write0 is like skip for outbound packets. It just writes 0 bytes though. So that line would add 00 00 00 00 00 to the packet (we had 13 00 before). Now it looks like 13 00 00 00 00 00 00. After the 4th line, the 5th line returns the packet, so it will return what we had at the 4th line.

Checking Packets for Inbound - Continued:
One way to check is to just compare the packets from the old version to the new one. Another way is to do the same thing we did for receive packets and check them byte by byte and seeing if it makes sense. The latter method works better during updates since if the packets don't match, we would have to trace it again through anyways to see if anything was incorrect. Refer to the other section to read and go through a packet. Remember that a byte is 1 byte, short is 2 bytes, int is 4 bytes, and a long is 8 bytes. If it is done correctly, the new packet for enabling a few functions will match the old one. The only difference between v88 and v98+ is that the opcode changed from 0x12 to 0x13, but this can be figured out by updating opcodes, which is why opcodes should be updated first.

Notes:
A few terms and sentences were simplified for better understanding. One example is what MaplePacketLittleEndianWriter is. Another example is what the return statement is. The benefit is that understanding this stuff really has no purpose in updating one version to another.

Other Packet Methods in Odin:

There are a few functions that have not been mentioned up until now. One of the most important methods in the source is readMapleAsciiString. This is like 2 functions in one. readMapleAsciiString will first pass over a short to get how long the string will be. Then it will read that length and convert the value to ASCII. For example if you had 08 00 30 30 30 30 30 30 30 30 and applied readMapleAsciiString, it would first read 08 00 (which is 8), then it would read 8 bytes and change that into ASCII. The 30s will become 0s. There is also the write counterpart of readMapleAsciiString, which is writeMapleAsciiString. writeMapleAsciiString("3141") would be 04 00 33 31 34 31. The 04 00 would be the length of the string that is being written.

There is a method called skip for reading bytes (and it has been gone over above). It merely just passes through the bytes in an outbound packet and doesn't do anything with the values excepts "skips" over. The other ones like readInt return an int value of the bytes it has passed. The write counterpart for skip would be write0 which writes 0s a number of times. It is not an exact counterpart, but it is similar.

There is a method for writing packets called writeAsciiString. This is the same as writeMapleAsciiString except the short indicating the length is not there. writeMapleAsciiString("1234") would write 04 00 31 32 33 34 while writeAsciiString("1234") would just be 31 32 33 34.

Summary of Updating Packets:
1. Check the packet
2. If it is incorrect, find out why it is incorrect. If there are new things added, figure out what it is supposed to represent. Barely anything is random, and even if something is always 0, they might have a purpose in later versions.
3. Make changes as necessary. Sometimes bytes are removed.
4. Repeat this for all broken packets between versions.

Efficient Way of Updating:
Of course it is impractical to do the hard packets first and it is pretty dumb to just do the biggest packets with no prior knowledge.

Tips:
-In packets, if it involves items, think about which slot the item is in, item id, and other things to do with items such as item stats. This can help identify the new parts. In new things added in new versions, think about what the value can be. For example in v99 and 0A 00 00 00 was added in some character stat places. What could that be? Think about what has the value 10 in v99.
-Know some common values. The non expiring timestamp long appears in many places including skills, items, and a couple other places. The default map packet used for teleport rocks is used in a couple places too. Know common values to help aid yourself through this long process.
-Learn some packet structures. After doing this for a while, you should know that buffs have 4 longs (or 2 before aftershock, 2.5 in v88) in the beginning, then for every buff stat the buff contains, it does short, int, int. After that it has some other info. Char Info goes from skills to cooldowns, to quests, to completed quests, and to mini-games, and then to rings, and then to teleport rocks, and so on. This makes checking much faster.
-Know some checkpoints for packets. When I do stupid packets like getCharInfo (the super long WARP_TO_MAP one), I start at the teleport rock place and fix those ints, and then work my way up. For all packets containing the addCharLook, I know the structure to have a section with equips showing up and I would do that place first and then work myself up the packet. If you are just starting out though, try to work in order from the top. It is much easier and even though it is slower, you can never go wrong.
-Updating versions takes some sort of experience. Know what to do, remember it, and keep learning on the way. You can never be too good at updating.
-No such thing as "packet triples" so no data type has 3 bytes. I see that a few packet editors talk about things with 3 bytes at a time. This is wrong. Do not fall into the same hole.
-Don't give up right away. Packets take some time to get used to and it really isn't that easy, no matter what people say. I've seen many people say packets are easy end up asking me for packets. There are packets that I have to ask to check as well and if they were really that easy, they would be easy to explain (which is not true at all), and easy to figure out any packet.
 
Last edited:
bleh....
Loyal Member
Joined
Oct 15, 2008
Messages
2,898
Reaction score
1,129
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

To everyone that posted, please repost. I deleted them so he could have back to back posts to make it easier for people to learn.

@OnTopic: Great job again man. This will help a lot of people for sure.
 
Last edited:
Banned
Banned
Joined
Jun 27, 2011
Messages
47
Reaction score
10
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

nice guide bro this will help me plenty xd, what was i even supposed to do anyway???????
 
Joined
Jun 5, 2010
Messages
567
Reaction score
598
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

will continue tomorrow. I have started on reading packets/updating structure but I need to make it understandable and not use definitions before defining them properly enough. It's kind of late to be writing something big like this so I will put it off until later. I don't think I'd be making much sense writing something that takes thinking at 2 am

About it being noob friendly, this really is about as noob friendly as it can get other than adding pictures (which will come when I'm done!). There are a few technical terms that need to be worked on later for lucidness though.
 
Banned
Banned
Joined
Jun 27, 2011
Messages
47
Reaction score
10
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

i get it and im the biggest noob so noobs you guys should get it

@SuperLol - Can you explain to us noobs about Serializable too?
 
wat
Loyal Member
Joined
Dec 27, 2007
Messages
369
Reaction score
7
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

This was a really detailed guide and I really appreciate you for the time you're taking to explain to us about this vague area.

Thank you :)
 
Legendary Battlemage
Loyal Member
Joined
Dec 13, 2010
Messages
649
Reaction score
140
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

This will surely motivate me to start sniffing, after I deleted my sniffer I never found any motivation to download it again, now with this as my reference, maybe I can make some progress here. Thanks Moogra.
 
Newbie Spellweaver
Joined
Apr 12, 2008
Messages
67
Reaction score
6
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

Thanks a lot for this. This is the most informative guide in maplestory guide section. Now its time to read everything. :]
 
M

MapleFanatic

Guest
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

Thx mang :] great guide. Always wanted to learn :)
 
Joined
Jun 5, 2010
Messages
567
Reaction score
598
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

I wrote a bit more about working with packet structures, will finish that up tomorrow (at least part 2)
 
Joined
Aug 10, 2008
Messages
858
Reaction score
516
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

HP and MP are integers post-BB (I was just assuming you meant those with stats also, since they are stats).

Edit: Otherwise, I'm going to just leave my comments aside until you're done. So far it looks good.
 
Last edited:
Divine Celestial
Loyal Member
Joined
Sep 29, 2008
Messages
804
Reaction score
219
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

Sexy wall of text is sexy wall of text.

Thank you :)

Misunderstood some parts but will re-read it when I actually start sniffing. Lol.
 
Newbie Spellweaver
Joined
Feb 4, 2011
Messages
37
Reaction score
1
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

This is actually worth the reading, it cleared a very good part of what most of us did not understand. I hope I am not asking for much on this one, I really don't want it to be spoonfed, but explained on what is needed to make your private server to a higher version, it could be the version itself, and not tell us how to get in-game, but +1 on this Moongra.
 
Newbie Spellweaver
Joined
Apr 18, 2011
Messages
49
Reaction score
1
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

I acutally read this all..

Excellent guide man.
 
may web.very maple.pls.
Loyal Member
Joined
Aug 12, 2009
Messages
1,810
Reaction score
606
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

nice nice I've learn a few things and so let me do a little test:
Information:
PHP:
//v.83
Received MOVE_SUMMON [00A2] (26)
[header"A2 00] [42 73 55 00] [gm"00] [?10 00] [text"52 3E 42 50 71 20 20 53 3E 47 46 41 20 37 6D 21] [show?"00]
¢.BsU....R>BPq  S>GFA 7m!.

//v.99
Received CHATTEXT [00C2] (13) 
[header"C2 00] [DD 0C 02 00] [gm"00] [?03 00] [text"68 65 79] [show?"00]
Â.Ý......hey.
PHP:
    public static MaplePacket getChatText(int cidfrom, String text, boolean gm, int show) {
        MaplePacketLittleEndianWriter mplew = new MaplePacketLittleEndianWriter();//TODO since theres a limit in text in global
        mplew.writeShort(0xC2);
        mplew.writeInt(cidfrom);
        mplew.write(gm ? 1 : 0);
        mplew.writeShort(text.length() > 10 : 10 : text.length()); // I'm guessing the text length if past 10 stays in 10/0A?
        mplew.writeMapleAsciiString(text);//add a getRightPaddedStr prob?
        mplew.write(show);
        return mplew.getPacket();
    }
I've updated from v.83 to v.97 and learned a bit on packet, so I was thinking why not test my ability here to make sure I'm doing this correctly..first time I've played with packets and upgraded..
 
Last edited:
Custom Title Activated
Loyal Member
Joined
Jun 30, 2008
Messages
3,451
Reaction score
1,616
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

Nooooo, my knowledge :(

---------- Post added at 07:18 PM ---------- Previous post was at 07:16 PM ----------

Uhm, akira? Wtf?
writeMapleAsciiString contains the length
 
Joined
Jun 5, 2010
Messages
567
Reaction score
598
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

nice nice I've learn a few things and so let me do a little test:
Information:
I've updated from v.83 to v.97 and learned a bit on packet, so I was thinking why not test my ability here to make sure I'm doing this correctly..first time I've played with packets and upgraded..

You need to read part 2 of the guide, especially where mapleAsciiString is mentioned.

Here's something though:
writeMapleAsciiString is
writeShort(string.length());
writeAsciiString(string);
 
Custom Title Activated
Loyal Member
Joined
Jun 30, 2008
Messages
3,451
Reaction score
1,616
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

You need to read part 2 of the guide, especially where mapleAsciiString is mentioned.

Here's something though:
writeMapleAsciiString is
writeShort(string.length());
writeAsciiString(string);
Commands like /packet are really useful for opcodes too.
And this can come handy too:
Code:
/*
	This file is part of the OdinMS Maple Story Server
    Copyright (C) 2008 Patrick Huy <patrick.huy@frz.cc>
		       Matthias Butz <matze@odinms.de>
		       Jan Christian Meyer <vimes@odinms.de>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation version 3 as published by
    the Free Software Foundation. You may not use, modify or distribute
    this program under any other version of the GNU Affero General Public
    License.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package net.server.handlers;

import client.MapleClient;
import net.MaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;

public class CustomPacketHandler implements MaplePacketHandler {
    @Override
    public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
        if (slea.available() > 0 && c.gmLevel() == 4) {//w/e       
            c.getSession().write(MaplePacketCreator.customPacket(slea.read((int) slea.available())));
        }
    }

    @Override
    public boolean validateState(MapleClient c) {
        return true;
    }
}
 
Newbie Spellweaver
Joined
Apr 12, 2008
Messages
67
Reaction score
6
Re: Updating a Server from One Version to Another [Wall of Text/Unfinished]

Can someone explain this part a little more deep? "It is also useful to know some basics such as 0xA = 10, 0xB = 11" I mean like 0x1A = How much (I think its 20, but I'm not sure)

EDIT: Woops, did a little research, and now I understand it totally. :)
 
Last edited:
Back
Top