leorbmello
Member-
Posts
12 -
Joined
-
Last visited
Reputation
1 NeutralPersonal Information
-
Location
New York
Recent Profile Visitors
The recent visitors block is disabled and is not being shown to other users.
-
Hello everyone, I am probably posting this in the wrong section, as there doesn't seem to be a dedicated area for Eudemons Online. I apologize in advance, and if you, Spirited, could create one, I would greatly appreciate it!!!! For the past few years, I have been developing a new server engine for Eudemons Online. I've been working on it gradually, taking the time to study and reverse engineer the Chinese server sources that have circulated throughout the community. Most of these projects are based on the same server engine that was originally released around 2006 (possibly even earlier), dating back to the Alpha/Beta stages of the game. As a result, they contain many adaptations and workarounds accumulated over the years. While they often emulate the game reasonably well, they are rarely accurate and, in many cases, implement mechanics incorrectly. Over time, I obtained two different official NpcServer binaries. The first came from the GlobalGames leak, and the second is a newer version from 2019 that was released with the Steam edition of the game. I spent a significant amount of time reversing both versions and rebuilding their functionality from scratch into a completely new and fully functional implementation. The biggest challenge is that, unlike Conquer Online, Eudemons Online has very few publicly available leaks, references, research materials, or reverse-engineering resources. Because of this, I would like to ask for help from anyone who has access to the MsgServer binary from either the GlobalGames version or the Steam release and would be willing to provide a reversed .c source for analysis and further restructuring. At this point, the server engine I have developed already supports virtually all major game features with very few bugs. In fact, it is considerably more accurate and faithful to the original game behavior than many of the older Paladin-based releases that appeared over the years. I have also developed tools capable of reading and editing the game's core file formats (.dat, .fdb, server.dat, etc.), allowing complete customization of game content and mechanics. Currently, I am using the American client version 2190 and have implemented the Vampire, Necromancer, Shadow Knight, and Ranger classes almost entirely from scratch. If someone can help with obtaining additional information or research material, I would greatly appreciate it. In return, I would be happy to start sharing some of the systems and techniques I have developed with anyone interested in learning, researching, or even building a future server project from the ground up. I'll leave a few screenshots below to showcase the current state of the project. The engine is stable, functional, and built by combining modern server architecture concepts with knowledge gathered from available Conquer Online sources. I also had the privilege of working alongside a close programming friend who provided valuable Conquer Online code references that helped us compare implementations and identify the best approaches for Eudemons Online. Thank you, and any contribution or information would be greatly appreciated.
-
leorbmello started following Konichu
-
Just wondering if there is any benefit to "winding" down these maps if they had no activity for a while? I.e. turning off generators for those specific maps and trying to get it to unload from memory? Is that instead too risky to do once it's already loaded and thus better to just hold the high memory usage? I recognize that maintenance sorts these issues out but figured I'd ask. Thanks! I believe I may have been wrong about what I really meant ... I do not remove what has already been created from monsters on the map, I just stop processing the respawn until a player returns to that map, avoiding creating entities that will not be active (this does not delete or remove the monsters that have already been created) previously) As for the loading of the map, I do not see any problem for now in working in this way, since important maps are always loaded. What stops being processed is just the generator. It was a simple idea, it may not be good in the long run, for now it is working well and without complaints, it is just a way to reduce the use of Generator'sThread. It would be pretty bad if i had to be reprocessing and recreate every entity on the map every time it's been out of use. Also, i guess for dynamaps, you could create something like: ConcurrentDictionary> Objects main index as MAP id and second entityID and role object... (stupid idea) this way you could use a single title base to hold some event maps as arena, you would not need to recreate the entire floor...
-
I don't know if it will help you, but... Like Spirited said, it saved me alot of memory usage. I made the server load basically all maps patch (GameMap.dat) and load just a few maps... most important ones, like city maps and quest maps. the most used ones, they're just a few, so.... The others if they would be used, the system loads the map when someone teleport there (yeah, you may feel like laggy when teleport to it for first time, but take no more than 2 or 3 seconds to the server load the map) and if the map has monsters or generator, the generator start just when the map has been activated.
-
For sure i will!
-
Well, i found the problem! Tq changed the StringLenght offset to Ushort, so, if i would write a string to a packet the structure now is: (Ushort) Value.Lenght (String) Value
-
It seems the packet is using the ProtoBuf... this makes a lot of sense, tested using protobuf at the MsgTaskDialog and i got some things working now, but not with the UserInfo one yet.... i checked out for 0x404 and from what i've seen it is 0x408, sometimes 0x410... so i don't really got yet.
-
Hey let's populate this forum hehe I'm using the Client version 6907 and i used the MACOS Client like Spirited's tutorial and i got the packet structures for two basic things that i'm having problens at this version. 1st: The CMsgUserInfo does not spawn the character name, but everything else is set correctly. 2nd: The CMsgTaskDialog (Npc Dialogs) i can spawn the picture and the box but not the texts. So, i'm trying to understand the whole thing, i got many things working already Here we have the Packet base Constructors but the things seems to have changed a lot from the older clients, or am i missing something basic. int __ZN12CMsgUserInfoC2Ev() { CNetMsg::CNetMsg(); *rdi = 0x101a66a50; CNetStringPacker::CNetStringPacker(); CNetMsg::Init(); *(rdi + 0x408) = rdi + 0x8; rax = CNetStringPacker::SetBuf(rdi + 0x410, rdi + 0xa1); return rax; } int __ZN12CMsgUserInfo6CreateEPcj(int * arg0, unsigned int arg1) { rbx = arg0; rcx = CNetMsg::Create(arg0, arg1); rax = 0x0; if (rcx != 0x0) { rax = (*(int16_t *)(rbx + 0xa) & 0xffff) == 0x8ad ? 0x1 : 0x0; } return rax; } This is the CMsgUserInfo::Process (when client receives the packet from server and build the Hero), it was very interesting to see how the things go this far, i've ben for hours to check it and i'm getting excited to learn more about those things, so here we go. The code is big so i removed the end of it because there is a limit of the characteres to post this. I could identify nearly all offsets, and they match for sure with the tests. The name is missing, but, i would like to understand why the name is being set at first, the offsets are set into the order from id to the final of the packet, so.... Is the name before the Character informations, or am i wrong? Other thing is, the strings 3 strings (name, last name and mate) are set to max lenght (32), i could see it at the beggining of the method... The 0xa1(161) is the base packet lenght and the other 0x8ad(2221) is the packet id. Obs.: Also i would love to discuss this at discord with someone, i really want to learn more about this.
-
Aww thanks, good point, i've checked the wiki and also got nearly all offsets of the packet, just missing the name one. Gonna try the disassembler, thanks!
-
I've already setup the msg action correctly and some other packets, but i have a problem with showing the character name on the client with the character info, seems i'm missing the offset... i've tested the trial and error like building and rebuilding, offset by offset... but i didn't make it... i could spawn all character main informations correctly, but not the name... from what i've seen, the ShowName offset has been removed, is that correct? By the way, this will be a opensource project... i just want to setup the basics.
-
The problem was just the ActionType... i was sending it wrong, i can login already, i just have to work on the positions now.
-
Hi guys, I might need a help on understanding what am i missing here. * Client version 6907 I already know that the packet id's have changed and already updated the packet id list. From what i can see, the client is ready to display the character at the screen and so on... but i get stuck at Initializing after sending the CofirmLocation information, it seems i'm missing something at the login sequence to get there. Well, this is the message action handler: public void MsgActionHandler(ClientSocket pClient, byte[] buffer) { MsgAction pInfo = new MsgAction(buffer); switch (pInfo.Action) { case MsgActionType.ConfirmLocation: { // send location to the client pClient.Send(new MsgAction(pClient.Character.Identity, 10160, pClient.Character.PosX, pClient.Character.PosY, MsgActionType.ConfirmLocation)); // load character inventory and equipments before spawn to others. // pClient.Character.LoadInventory(); // pClient.Character.LoadEquipment(); // // execute the entermap (load screen and etc) pClient.Character.EnterMap(); break; } /*case MsgActionType.ConfirmHotkeys: { //pClient.Send(pInfo); break; } case MsgActionType.ConfirmFriends: { // pClient.Send(pInfo); break; } case MsgActionType.ConfirmProficiencies: { // pClient.Character.SendCharacterProfs(); // pClient.Send(pInfo); break; } case MsgActionType.ConfirmSpells: { // pClient.Character.SendCharacterMagics(); // pClient.Send(pInfo); break; } case MsgActionType.ConfirmGuild: { // pClient.Send(pInfo); break; } case MsgActionType.ConfirmLogin: { // pClient.Send(pInfo); break; } case MsgActionType.ChangeFlyMapPortal: { if(!WorldManager.Portals.ContainsKey(pClient.Character.MapIdentity)) { Program.WriteLine("Invalid mapportal at : " + pClient.Character.MapIdentity + "(" + pClient.Character.PosX + ", " + pClient.Character.PosY + ")"); pClient.Character.FlyMap(1002, 430, 380); return; } PortalInfo pPortal = null; foreach (PortalInfo pPortalInfo in WorldManager.Portals[pClient.Character.MapIdentity].Values) if (pPortalInfo.PosX == pInfo.LeftData0 && pPortalInfo.PosY == pInfo.RightData0) { pPortal = pPortalInfo; break; } if (pPortal == null) { Program.WriteLine("Invalid passway at : " + pClient.Character.MapIdentity + "(" + pClient.Character.PosX + ", " + pClient.Character.PosY + ")"); pClient.Character.FlyMap(1002, 430, 380); return; } pClient.Character.FlyMap(pPortal.TargetMap, pPortal.TargetPosX, pPortal.TargetPosY); break; } case MsgActionType.PlayerJump: { pClient.Character.MovePos(MoveModeType.Jump, 0, pInfo.LeftData0, pInfo.RightData0, pInfo); break; }*/ case MsgActionType.ChangePKMode: { pInfo.Info.dwParam3 = pInfo.Info.dwParam; pClient.Send(pInfo); break; } default: { Program.WriteLine(String.Format("Missing MsgAction Handler: {0}[{1}]", pInfo.Action, (int)pInfo.Action)); Report(buffer); pClient.Send(pInfo); break; } } } When i send the ConfirmLocation, the client replies the ChangePK packet... From what i could check, the new versions are using the ProtoBuffer to build some packets, so i tested using this structure for the MsgAction: [ProtoContract] public class MsgActionInfo { [ProtoMember(1, IsRequired = true)] public uint Identity; [ProtoMember(2)] public uint Target; [ProtoMember(3)] public uint dwParam; [ProtoMember(4)] public int dwParam2; [ProtoMember(5)] public long dwParam3; [ProtoMember(6)] public bool SucDone; [ProtoMember(7)] public uint TargetPositionX; [ProtoMember(8)] public uint TargetPositionY; [ProtoMember(9, IsRequired = true)] public uint Timestamp; [ProtoMember(10)] public int TargetNpcIdentity; [ProtoMember(11)] public uint CheatLogData1; [ProtoMember(12, IsRequired = true)] public ushort Type; [ProtoMember(13, IsRequired = true)] public ushort Facing; [ProtoMember(14, IsRequired = true)] public uint PositionX; [ProtoMember(15, IsRequired = true)] public uint PositionY; [ProtoMember(16)] public uint CheatLogData2; [ProtoMember(17)] public uint MapID; [ProtoMember(18)] public uint CheatLogData3; [ProtoMember(19)] public int ScheduleTime; [ProtoMember(20)] public int LinkIndex; [ProtoMember(21)] public uint CheatLogData4; [ProtoMember(22)] public int RemainTime; [ProtoMember(23)] public bool MountCharge; [ProtoMember(24)] public List<byte[]> Strings; } And i got stuck here: Is there something new to the ConfirmLocation, or is the packet structure wrong?