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!

GMS - Like V38 Server

Newbie Spellweaver
Joined
Aug 7, 2013
Messages
30
Reaction score
3
I even suggest going lower: v28. v28 seems like the most stable GMS version, as it had Aqua Road - which is the best place for higher levels to train. However, the 4th generation of MapleStory (v30 to v39) had things like Amoria, Amoria Dungeon, Guild Quest, Orbis PQ, Quest Helper, Korean Folk Town, and the new tutorial (Which is pretty awesome, but still). Those are things which ruined the game, in my opinion.

v38 also had an awesome login screen.
ModdedMushroom - GMS - Like V38 Server - RaGEZONE Forums

V38 MSSetup was unfortunately the lowest version I could find anywhere :/ Trust me, if I had a v28 localhost and a setup, I'd much rather work on that

*Edit*
I just read the rest of this post, for I had not seen there were multiple pages when I replied
 
Junior Spellweaver
Joined
Nov 29, 2008
Messages
168
Reaction score
7
This is a useless argument. I clearly contributed more to this community than you ever did (if you did at all). I'm simply implying what you reflect. Your so talked MapleEllin was just a big bluff, even if it weren't - you're using things that are already released.

Moreover, your attempts to steal stuff from me (or from other members) have failed miserably, so you threatened to "quit", but then again - you're here, which just proves my point. Additionally, you just asked Kiki to create a LEN (or whatever) for your "server" so you have a shortcut because you can't make anything yourself.

Pretty sure this guy isn't the guy you're talking about. This guy is just the guy who keeps quitting and coming back, but he doesn't make servers to my knowledge.
 
Newbie Spellweaver
Joined
May 28, 2012
Messages
68
Reaction score
2
Hi Kiki, can you make us a v50 Localhost I do love to work on that version.

You can download the v50 setup from here:

 
Joined
Apr 10, 2008
Messages
4,087
Reaction score
1,264
Pretty sure it either doesn't have the custom encryption, or it's different.

I can try to reverse engineer the encryption function a bit later on.

Just wanted to write here in case Kiki visits next time. The v28 client does seem to have a CRC when migrating to the game server. I updated everything and once I select the character the client immediately crashes with no error or what-so-ever. I'll attempt to debug it and see.
 
Newbie Spellweaver
Joined
Mar 19, 2006
Messages
50
Reaction score
59
Just wanted to write here in case Kiki visits next time. The v28 client does seem to have a CRC when migrating to the game server. I updated everything and once I select the character the client immediately crashes with no error or what-so-ever. I'll attempt to debug it and see.

Seems to work fine for me :)

eOMRaJ - GMS - Like V38 Server - RaGEZONE Forums
 

Attachments

You must be registered for see attachments list
Joined
Apr 10, 2008
Messages
4,087
Reaction score
1,264
Seems to work fine for me :)

eOMRaJ - GMS - Like V38 Server - RaGEZONE Forums

Hmm, weird. I suppose it may be because my client has AES skipped in it? I tried yours, but it seems like the encryption is fucked, so mine has AES skipped in it. I use the v55's key for it:

Code:
byte key[] = { 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00,
			0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00 };
 

Attachments

You must be registered for see attachments list
Newbie Spellweaver
Joined
Mar 19, 2006
Messages
50
Reaction score
59
Hmm, weird. I suppose it may be because my client has AES skipped in it? I tried yours, but it seems like the encryption is fucked, so mine has AES skipped in it. I use the v55's key for it:

Code:
byte key[] = { 0x13, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, (byte) 0xB4, 0x00, 0x00,
			0x00, 0x1B, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x33, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00 };

I'm using the v28_noaes.exe client that someone uploaded before.

I've probably made some edits to it though, so just incase here's the download -

Relevant game login stuff (from my server, but I'm sure you can figure out what it should be doing :)):

GameClientSocket class:
Code:
        protected bool on_migrate_in(InPacket packet)
        {
            bool result = false;

            if (m_eMigrateState == MigrateState.NotStarted)
            {
                m_uCharacterID = packet.decode4();
                m_bAdminClient = packet.decode1() == 1 ? true : false;

                m_eMigrateState = MigrateState.ClientLogin;

                User user = GameApp.db.get_user(m_uCharacterID);
                if (user != null)
                {
                    m_User = user;
                    m_User.m_socket = this;
                    return user.on_migrate_in_success(); // User class reference
                }
            }

            return result;
        }

User class:
Code:
        public bool on_migrate_in_success()
        {
            if (m_character.m_characterStat.m_nHP == 0)
            {
                m_character.m_characterStat.m_nHP = 50;
            }

            Field field = FieldMan.instance().get_field(m_character.m_characterStat.m_nPosMap);

            if (field != null)
            {
                m_field = field;

                Portal pt = m_field.m_portal.get_rand_start_point();

                if (pt != null)
                {
                    m_ptCurPos = new Point()
                    {
                        X = pt.m_ptPos.X,
                        Y = pt.m_ptPos.Y
                    };

                    m_character.m_characterStat.m_bPortal = (byte)pt.m_nIdx;

                    if (send_set_field_packet(true))
                    {
                        return m_field.on_enter(this);
                    }
                }
            }

            return false;
        }

        public bool send_set_field_packet(bool character_data)
        {
            OutPacket op = new OutPacket(Opcodes.Server.Stage_SetField);
            op.encode4(0);
            op.encode1(++m_bCurFieldKey);
            op.encode1(character_data);

            if (character_data)
            {
                uint r1 = GameApp.rand.random();
                uint r2 = GameApp.rand.random();
                uint r3 = GameApp.rand.random();

                m_calcDamage.set_seed(r1, r2, r3);
                op.encode4(r1);
                op.encode4(r2);
                op.encode4(r3);
                op.encode4(GameApp.rand.random());

                m_character.encode(op, -1); // CharacterData class reference
            }
            else
            {
                op.encode4(m_character.m_characterStat.m_nPosMap);
                op.encode1(m_character.m_characterStat.m_bPortal);
                op.encode2(m_character.m_characterStat.m_nHP);
                op.encode1(m_bChase);

                if (m_bChase)
                {
                    op.encode4(m_nTargetPosition_X);
                    op.encode4(m_nTargetPosition_Y);
                }
            }

            return send_packet(op);
        }

CharacterData class:
Code:
        public void encode(OutPacket packet, Int16 uflag)
        {
            packet.encode2(uflag);

            if ((uflag & 1) != 0)
            {
                m_characterStat.encode(packet); // GW_CharacterStat class reference
                packet.encode1((char)m_nFriendMax);
            }

            if ((uflag & 2) != 0)
            {
                m_characterStat.encode_money(packet); // GW_CharacterStat class reference
            }

            if ((uflag & 0x80) != 0)
            {
                for (InventoryType it = InventoryType.IT_EQUIP; it < InventoryType.IT_EXNO; it++)
                {
                    packet.encode1((byte)m_aItemSlotCount[(int)it]);
                }
            }

            if ((uflag & 4) != 0)
            {
                for (int i = 1; i < m_aEquipped.Length; i++)
                {
                    if (m_aEquipped[i] != null)
                    {
                        packet.encode1((byte)i);
                        m_aEquipped[i].p.encode(packet);
                    }
                }
                packet.encode1(0); // end of equipped

                for (int i = 1; i < m_aEquipped2.Length; i++)
                {
                    if (m_aEquipped2[i] != null)
                    {
                        packet.encode1((byte)i);
                        m_aEquipped2[i].p.encode(packet);
                    }
                }
                packet.encode1(0); // end of masked equipped
            }

            for (InventoryType it = InventoryType.IT_EQUIP; it < InventoryType.IT_EXNO; it++)
            {
                Int16 p = 0;
                switch (it)
                {
                    case InventoryType.IT_EQUIP: p = 4; break;
                    case InventoryType.IT_CONSUME: p = 8; break;
                    case InventoryType.IT_INSTALL: p = 0x10; break;
                    case InventoryType.IT_ETC: p = 0x20; break;
                    case InventoryType.IT_CASH: p = 0x40; break;
                }

                if ((p & uflag) != 0)
                {
                    for (Int16 i = 1; i <= m_aItemSlotCount[(int)it]; i++)
                    {
                        if (m_aaItemSlot[(int)it].ContainsKey(i))
                        {
                            packet.encode1((byte)i);
                            m_aaItemSlot[(int)it][i].p.encode(packet);
                        }
                    }
                    packet.encode1(0); // end of inv(n)
                }
            }

            if ((uflag & 0x100) != 0)
            {
                packet.encode2(0); // skill count
            }

            if ((uflag & 0x8000) != 0)
            {
                packet.encode2(0); // skill cooltime count
            }

            if ((uflag & 0x200) != 0)
            {
                packet.encode2(0); // quest record count
            }

            if ((uflag & 0x4000) != 0)
            {
                packet.encode2(0); // quest complete count
            }

            if ((uflag & 0x400) != 0)
            {
                packet.encode2(0); // minigame record count
            }

            if ((uflag & 0x800) != 0)
            {
                //packet.encode2(0); // couple record count

                packet.encode2((UInt16)m_lFriendRecord.Count); // friend record count

                foreach (GW_FriendRecord fr in m_lFriendRecord)
                {
                    fr.encode(packet);
                }

                //packet.encode2(0); // marriage record count
            }

            if ((uflag & 0x1000) != 0)
            {
                foreach(uint map_id in m_auMapTransfer)
                {
                    packet.encode4(map_id);
                }

                foreach (uint map_id in m_auMapTransferEx)
                {
                    packet.encode4(map_id);
                }
            }
        }

GW_CharacterStat class:
Code:
        public void encode(OutPacket packet)
        {
            packet.encode4(m_uCharacterId);

            byte[] buff = new byte[13];
            Buffer.BlockCopy(Encoding.ASCII.GetBytes(m_sName), 0, buff, 0, m_sName.Length);

            packet.encode_buffer(buff);
            packet.encode1(m_nGender);
            packet.encode1(m_bSkin);
            packet.encode4(m_uFace);
            packet.encode4(m_uHair);
            packet.encode_buffer(m_liPetLockerSN);
            packet.encode1(m_bLevel);
            packet.encode2(m_uJob);
            packet.encode2(m_nStr);
            packet.encode2(m_nDex);
            packet.encode2(m_nInt);
            packet.encode2(m_nLuk);
            packet.encode2(m_nHP);
            packet.encode2(m_nMaxHP);
            packet.encode2(m_nMP);
            packet.encode2(m_nMaxMP);
            packet.encode2(m_uAP);
            packet.encode2(m_uSP);
            packet.encode4(m_nEXP);
            packet.encode2(m_nPop);
            packet.encode4(m_nPosMap);
            packet.encode1(m_bPortal);
        }

        public void encode_money(OutPacket packet)
        {
            packet.encode4(m_nMoney);
        }
 
Joined
Apr 10, 2008
Messages
4,087
Reaction score
1,264
I'm using the v28_noaes.exe client that someone uploaded before.

I've probably made some edits to it though, so just incase here's the download -

Relevant game login stuff (from my server, but I'm sure you can figure out what it should be doing :)):

GameClientSocket class:
Code:
        protected bool on_migrate_in(InPacket packet)
        {
            bool result = false;

            if (m_eMigrateState == MigrateState.NotStarted)
            {
                m_uCharacterID = packet.decode4();
                m_bAdminClient = packet.decode1() == 1 ? true : false;

                m_eMigrateState = MigrateState.ClientLogin;

                User user = GameApp.db.get_user(m_uCharacterID);
                if (user != null)
                {
                    m_User = user;
                    m_User.m_socket = this;
                    return user.on_migrate_in_success(); // User class reference
                }
            }

            return result;
        }

User class:
Code:
        public bool on_migrate_in_success()
        {
            if (m_character.m_characterStat.m_nHP == 0)
            {
                m_character.m_characterStat.m_nHP = 50;
            }

            Field field = FieldMan.instance().get_field(m_character.m_characterStat.m_nPosMap);

            if (field != null)
            {
                m_field = field;

                Portal pt = m_field.m_portal.get_rand_start_point();

                if (pt != null)
                {
                    m_ptCurPos = new Point()
                    {
                        X = pt.m_ptPos.X,
                        Y = pt.m_ptPos.Y
                    };

                    m_character.m_characterStat.m_bPortal = (byte)pt.m_nIdx;

                    if (send_set_field_packet(true))
                    {
                        return m_field.on_enter(this);
                    }
                }
            }

            return false;
        }

        public bool send_set_field_packet(bool character_data)
        {
            OutPacket op = new OutPacket(Opcodes.Server.Stage_SetField);
            op.encode4(0);
            op.encode1(++m_bCurFieldKey);
            op.encode1(character_data);

            if (character_data)
            {
                uint r1 = GameApp.rand.random();
                uint r2 = GameApp.rand.random();
                uint r3 = GameApp.rand.random();

                m_calcDamage.set_seed(r1, r2, r3);
                op.encode4(r1);
                op.encode4(r2);
                op.encode4(r3);
                op.encode4(GameApp.rand.random());

                m_character.encode(op, -1); // CharacterData class reference
            }
            else
            {
                op.encode4(m_character.m_characterStat.m_nPosMap);
                op.encode1(m_character.m_characterStat.m_bPortal);
                op.encode2(m_character.m_characterStat.m_nHP);
                op.encode1(m_bChase);

                if (m_bChase)
                {
                    op.encode4(m_nTargetPosition_X);
                    op.encode4(m_nTargetPosition_Y);
                }
            }

            return send_packet(op);
        }

CharacterData class:
Code:
        public void encode(OutPacket packet, Int16 uflag)
        {
            packet.encode2(uflag);

            if ((uflag & 1) != 0)
            {
                m_characterStat.encode(packet); // GW_CharacterStat class reference
                packet.encode1((char)m_nFriendMax);
            }

            if ((uflag & 2) != 0)
            {
                m_characterStat.encode_money(packet); // GW_CharacterStat class reference
            }

            if ((uflag & 0x80) != 0)
            {
                for (InventoryType it = InventoryType.IT_EQUIP; it < InventoryType.IT_EXNO; it++)
                {
                    packet.encode1((byte)m_aItemSlotCount[(int)it]);
                }
            }

            if ((uflag & 4) != 0)
            {
                for (int i = 1; i < m_aEquipped.Length; i++)
                {
                    if (m_aEquipped[i] != null)
                    {
                        packet.encode1((byte)i);
                        m_aEquipped[i].p.encode(packet);
                    }
                }
                packet.encode1(0); // end of equipped

                for (int i = 1; i < m_aEquipped2.Length; i++)
                {
                    if (m_aEquipped2[i] != null)
                    {
                        packet.encode1((byte)i);
                        m_aEquipped2[i].p.encode(packet);
                    }
                }
                packet.encode1(0); // end of masked equipped
            }

            for (InventoryType it = InventoryType.IT_EQUIP; it < InventoryType.IT_EXNO; it++)
            {
                Int16 p = 0;
                switch (it)
                {
                    case InventoryType.IT_EQUIP: p = 4; break;
                    case InventoryType.IT_CONSUME: p = 8; break;
                    case InventoryType.IT_INSTALL: p = 0x10; break;
                    case InventoryType.IT_ETC: p = 0x20; break;
                    case InventoryType.IT_CASH: p = 0x40; break;
                }

                if ((p & uflag) != 0)
                {
                    for (Int16 i = 1; i <= m_aItemSlotCount[(int)it]; i++)
                    {
                        if (m_aaItemSlot[(int)it].ContainsKey(i))
                        {
                            packet.encode1((byte)i);
                            m_aaItemSlot[(int)it][i].p.encode(packet);
                        }
                    }
                    packet.encode1(0); // end of inv(n)
                }
            }

            if ((uflag & 0x100) != 0)
            {
                packet.encode2(0); // skill count
            }

            if ((uflag & 0x8000) != 0)
            {
                packet.encode2(0); // skill cooltime count
            }

            if ((uflag & 0x200) != 0)
            {
                packet.encode2(0); // quest record count
            }

            if ((uflag & 0x4000) != 0)
            {
                packet.encode2(0); // quest complete count
            }

            if ((uflag & 0x400) != 0)
            {
                packet.encode2(0); // minigame record count
            }

            if ((uflag & 0x800) != 0)
            {
                //packet.encode2(0); // couple record count

                packet.encode2((UInt16)m_lFriendRecord.Count); // friend record count

                foreach (GW_FriendRecord fr in m_lFriendRecord)
                {
                    fr.encode(packet);
                }

                //packet.encode2(0); // marriage record count
            }

            if ((uflag & 0x1000) != 0)
            {
                foreach(uint map_id in m_auMapTransfer)
                {
                    packet.encode4(map_id);
                }

                foreach (uint map_id in m_auMapTransferEx)
                {
                    packet.encode4(map_id);
                }
            }
        }

GW_CharacterStat class:
Code:
        public void encode(OutPacket packet)
        {
            packet.encode4(m_uCharacterId);

            byte[] buff = new byte[13];
            Buffer.BlockCopy(Encoding.ASCII.GetBytes(m_sName), 0, buff, 0, m_sName.Length);

            packet.encode_buffer(buff);
            packet.encode1(m_nGender);
            packet.encode1(m_bSkin);
            packet.encode4(m_uFace);
            packet.encode4(m_uHair);
            packet.encode_buffer(m_liPetLockerSN);
            packet.encode1(m_bLevel);
            packet.encode2(m_uJob);
            packet.encode2(m_nStr);
            packet.encode2(m_nDex);
            packet.encode2(m_nInt);
            packet.encode2(m_nLuk);
            packet.encode2(m_nHP);
            packet.encode2(m_nMaxHP);
            packet.encode2(m_nMP);
            packet.encode2(m_nMaxMP);
            packet.encode2(m_uAP);
            packet.encode2(m_uSP);
            packet.encode4(m_nEXP);
            packet.encode2(m_nPop);
            packet.encode4(m_nPosMap);
            packet.encode1(m_bPortal);
        }

        public void encode_money(OutPacket packet)
        {
            packet.encode4(m_nMoney);
        }

Thanks very much Kiki (-:

ModdedMushroom - GMS - Like V38 Server - RaGEZONE Forums


Also, what changes did you make to his client? Just wondering.
 
Newbie Spellweaver
Joined
Mar 19, 2006
Messages
50
Reaction score
59
Thanks very much Kiki (-:

ModdedMushroom - GMS - Like V38 Server - RaGEZONE Forums


Also, what changes did you make to his client? Just wondering.

No worries.

I can't remember exactly what I patched, but I know there was a bug in this client that made it crash when it tried to upload the last exception log. I think that was on client run though, not login to game server. Meh, either way if it's working then don't question the miracle :)
 
Newbie Spellweaver
Joined
May 28, 2012
Messages
68
Reaction score
2
Hey kiki can you please make a localhost for v50 Im so need it

 
Newbie Spellweaver
Joined
Mar 8, 2014
Messages
18
Reaction score
4
You could always backport features from a higher version into a lower one like my project did with v83, and 116 (e.g. backport v55 features into 38). I would take that concept into consideration over the course of your development because the one question that I'm sure has been burning in peoples heads is "why settle for one with less, or another with more?" when (with some elbow grease) you can create your own "version".

@Fraysa ... windows ... :thumbdown:
@tehkiki please refer to my last statement
 
Last edited:
Newbie Spellweaver
Joined
Mar 19, 2006
Messages
50
Reaction score
59
You could always backport features from a higher version into a lower one like my project did with v83, and 116 (e.g. backport v55 features into 38). I would take that concept into consideration over the course of your development because the one question that I'm sure has been burning in peoples heads is "why settle for one with less, or another with more?" when (with some elbow grease) you can create your own "version".

@Fraysa ... windows ... :thumbdown:
@tehkiki please refer to my last statement

I had plans to do this with my server too, but I sadly have so little time for MapleStory these days. I swear that I've wasted more than a whole year (as in more than 8760 hours) of my life just coding and reverse engineering :(

So is the concept of your "backporting" just downgrading a higher version client to a lower one (through content, etc)? If this is the case, then you probably don't want to go above v111.1 (i.e. when I last released a fully unpacked client) stuff beyond that is increasing hard to manipulate.

My idea was to actually use the different clients and either have different network ports for different versions OR create a generic hook for ClientSocket::ConnectLogin that sends a packet with the version number once connected.

Both kinda suck lol

tehkiki , thanks for the fixed localhost!

No worries, the original uploaded version has disappeared off of sendspace now anyway!
 
Newbie Spellweaver
Joined
Mar 8, 2014
Messages
18
Reaction score
4
I had plans to do this with my server too, but I sadly have so little time for MapleStory these days. I swear that I've wasted more than a whole year (as in more than 8760 hours) of my life just coding and reverse engineering :(
How much time you are willing to dedicate is a large factor.

So is the concept of your "backporting" just downgrading a higher version client to a lower one (through content, etc)? If this is the case, then you probably don't want to go above v111.1 (i.e. when I last released a fully unpacked client) stuff beyond that is increasing hard to manipulate.
I'm fail to see why what you have released pertains to what our team is up to ;)

Back on topic, Jeff had manually reverse engineered both of our clients before I had even gotten onto the project. We are literally rewriting portions of the version 83 client to add support for the upgraded systems found in the version 116, patching the version 83 client with the version 116 feature of choice, and moving forward onto the wz files and server implementation. On a side note I can't imagine how long it took Jeff to get us a pretty much totally open source version of these clients.

My idea was to actually use the different clients and either have different network ports for different versions OR create a generic hook for ClientSocket::ConnectLogin that sends a packet with the version number once connected.
We wrote our own implementation of the feature to solve this. So in other words your second idea was our solution.
 
Last edited:
Back
Top