- Joined
- Apr 10, 2008
- Messages
- 4,087
- Reaction score
- 1,264
You must be registered to see links
Can confirm this works, thank you very much kind sir!
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!You must be registered to see links
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.
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.
I will assume this died...?
Of course it is, I was in the funeral.
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.
Seems to work fine for me
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 };
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 };
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;
}
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);
}
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);
}
}
}
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);
}
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 -You must be registered to see links
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 (-:
Also, what changes did you make to his client? Just wondering.
Hey kiki can you please make a localhost for v50 Im so need it
Hey kiki can you please make a localhost for v50 Im so need it
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
tehkiki , thanks for the fixed localhost!
How much time you are willing to dedicate is a large factor.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
I'm fail to see why what you have released pertains to what our team is up toSo 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.
We wrote our own implementation of theMy 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.