Solo usuarios registrados pueden comentar y agradecer, Logueate o Registrate

Autor Topic: FPS Revolution for Main 5.2  (Visto 1969 veces)

0 Miembros and 1 Guest are viewing this topic.

Offline TranLam.Noria Posteado: August 05, 2025, 10:46:23 AM

  • 0 puntos por ventas
  • *
  • Rank: Principiante
  • Posts: 7
  • Gracias recibida: 25


Inspired by Takumi’s idea, we have optimized the entire rendering system of Mu Online. Now, in almost every situation, players can enjoy the game at a stable 60 FPS. As shown in the attached video, even with a GTX 750 Ti graphics card, I’m still able to play at 60 FPS with hundreds of moving characters and skill effects on screen (the video doesn’t fully reflect this due to a 10% FPS loss during Full HD 60 FPS recording).

With this algorithm, I don’t need to reduce visual effects, disable skills, or increase GPU usage percentage like some recently shared videos suggest. In my opinion, pushing GPU usage to 50-70% is practically unfeasible for Mu Online, since players often run 2-3 or even 10 game clients simultaneously. I can't imagine the FPS impact if just one client alone takes up 50-70% of the GPU.

There’s still room for further improvements, but I believe this is already more than enough for players to enjoy a smooth experience. Of course, it could be optimized further for stability, but it's likely unnecessary. The GPU I’m using is over 10 years old and only costs around $20 on the second-hand market. Any modern GPU today would outperform it many times over.

Instead of continuing optimization, I believe it would be better to invest time in porting Mu Online to mobile. This algorithm already helps maximize battery efficiency on today’s smartphones. If you share the same vision and want to collaborate with me to bring Mu Online to mobile, feel free to message me here, on Facebook, or on YouTube.

Thanks for reading.

Gracias:


Offline takumi12 #1 Posteado: August 05, 2025, 11:57:32 AM | Modificado: August 05, 2025, 12:22:10 PM by takumi12

  • MAESTRO

  • US. DE HONOR

  • LEYENDA

  • Php Coder
  • +11 puntos por ventas
  • *
  • *
  • Rank: Puto amo
  • Posts: 1.048
  • Gracias recibida: 45436
  • mx
People think that just using shader will give them the best game and mu online 60 fps.

This is a clear example that more is required than just implementing shaders. There are endless algorithms that need to be scaled to achieve a readable result: cullingface, bachrender, VBO, VAO. Shaders are just an implementation addition for improvement. If your algorithm is not efficient, adding them only harms performance consumption. Good project, and I'm glad to be part of the growth that mu online is starting to have.


SPN:
La gente cree que usar shaders les dará el mejor juego y MU Online a 60 fps.

Este es un claro ejemplo de que se necesita más que simplemente implementar shaders. Hay un sinfín de algoritmos que deben escalarse para lograr un resultado legible: cullingface, bachrender, VBO, VAO. Los shaders son solo una adición a la implementación para mejorar. Si tu algoritmo no es eficiente, añadirlos solo perjudica el rendimiento. Buen proyecto, y me alegra formar parte del crecimiento que MU Online está comenzando a tener.


Las offset no se crea, ni se destruye, solo se transforma

Gracias:


Offline lkt22 #2 Posteado: August 05, 2025, 12:50:47 PM

  • 0 puntos por ventas
  • *
  • Rank: Liga mayor
  • Posts: 194
  • Gracias recibida: 97
  • br

Offline kayito #3 Posteado: August 05, 2025, 09:49:44 PM

  • MAESTRO

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Puto amo
  • Posts: 1.083
  • Gracias recibida: 19865
  • ar
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

Gracias:


Offline takumi12 #4 Posteado: August 05, 2025, 11:14:30 PM | Modificado: August 05, 2025, 11:44:38 PM by takumi12

  • MAESTRO

  • US. DE HONOR

  • LEYENDA

  • Php Coder
  • +11 puntos por ventas
  • *
  • *
  • Rank: Puto amo
  • Posts: 1.048
  • Gracias recibida: 45436
  • mx
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}


Las offset no se crea, ni se destruye, solo se transforma

Gracias:


Online k33n00 #5 Posteado: August 06, 2025, 12:50:00 AM

  • 0 puntos por ventas
  • *
  • Rank: Dedicado
  • Posts: 31
  • Gracias recibida: 8
  • vn
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}
¿Puedes compartirme una copia?


Offline Feche #6 Posteado: August 06, 2025, 03:34:25 AM | Modificado: August 06, 2025, 05:21:01 PM by Feche

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Dedicado
  • Posts: 50
  • Gracias recibida: 1509
  • ar
El gran problema es que el juego usa modo inmediato - OpenGL 1.0 - y todo pero absolutamente todo el trabajo lo hace gran parte el CPU. Proyecciones, matrices, animación de objetos/texturas y muchas cosas más. Lo mas inoptimizado a mi parecer es el renderizado del terreno - por cada frame el juego escanea X cantidad de tiles/coordenadas y hace 2 pasadas de renderizado. Lo ideal seria mover todo los calculos de proyecciones, animaciónes de efectos, etc al GPU y que el CPU solo de ordenes, de esa manera se aprovecha la GPU (que es justamente para hacer ese tipo de cosas) y se le saca carga al CPU. Con lo basico que es el juego ni siquiera se nesecita multithreading, con tan solo delegar el trabajo correspondiente al GPU ya es suficiente.

Gracias:


Offline kayito #7 Posteado: August 06, 2025, 08:16:53 AM | Modificado: August 06, 2025, 08:26:08 AM by kayito

  • MAESTRO

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Puto amo
  • Posts: 1.083
  • Gracias recibida: 19865
  • ar
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}

Claro, entiendo perfectamente tu punto e incluso sé que se puede lograr sin necesidad de optar por un main bajo.

A lo que voy es que la arquitectura del software del juego no está pensada para ser escalada y todo se termina agregando con herramientas externas (los encoder para items, mapas, monstruos, efectos, etc.).

Entonces mi punto es, si ya se está optando por una buena refactorización del juego por qué no hacerla como corresponde optando por algo súper básico y volviendo a escalar añadiendo (COMO CORRESPONDE, NO COMO WEBZEN) cada sistema nuevamente de manera eficiente.
Como el ejemplo que di, el main 0.53 trae simplemente 3 personajes, 5 mapas, 16 items por categoría, sin evoluciones y sin eventos. Toda la lógica base para añadir el MG y el DL por ejemplo se pueden simplificar y unificar completamente en un sistema base donde agregar un personaje nuevo no requiera tocar diez millones de IF.

Ojo a esto, no me refiero a agregarlo por DLL sino a decompilar el main, tener un código compilable de un main muy reducido (la decompilación es más fácil guiándose con el source s5.2) y a partir de ahí trabajar en ese source pequeño y limpio.

Y ni hablemos de las sincronizaciones de datos. Montones de archivos podrían migrarse directamente a un sistema de solicitud hacia el servidor, aprovechando más el consumo de red que el consumo de cpu, optando por mejorar la sincronización con el servidor. (Ejemplos boludos: el chaos mix, los stats de la C, la información del viewport, el movelist, el listado de servidores del select server, etc.).

Creo yo que Webzen tiene un muy mal código integrado y que todas las funcionalidades fueron añadidas como se pudo simplemente para que funcionen y no se tuvo en cuenta que funcionen bien. Al menos yo considero que todos los mains tienen miles de problemas que se solucionan reescribiendo los sistemas de manera óptima.

Y por último, yo veo un aspecto un poco más amplio que sólo la Season 6. Entiendo que todos targeteen esa única versión y, a partir de ahí, quieran upgradear o downgradear. A mi parecer, es mucho más factible partir de algo súper nativo con sistemas muy simples, ya que refactorizar todo lo necesario sería mucho más sencillo teniendo poco código que manosear (el render es exactamente el mismo, nada más cambian tamaños de texturas y modelos un poco más complejos). Entonces una vez refactorizado algo nativo, se puede reescalar nuevamente y llevar a Season 6 o más, pero integrando cada sistema de manera óptima y refactorizada.
A lo que voy es que si mirás el código, más de la mitad está escrito de manera HORRENDA. Si tuvieras que refactorizar cada sistema uno por uno (las opciones de los items, los ancient, los harmony, los 380, los socket) qué te llevaría más? Agarrar una base limpia e ir agregándolos ya refactorizados o ir buscando dónde está cada sistema reescribiendo función por función, manteniendo la lógica pedorra de Webzen? Se entiende mi punto con esto?

Lo que propongo sería prácticamente reescribir el main nuevamente pero partiendo desde una base funcional mínima, en lugar de tener que refactorizar algo ya desorganizado y sin lógica de escalabilidad, ni buena arquitectura de software. Tampoco pretendo irme por las ramas como SirMaster, que planteó un proyecto remake escribiendo todo de 0 y, en todo el tiempo que invirtió no logró ni siquiera tener algo jugable. En este caso se parte de algo jugable pero mínimo y simplemente toca optimizar esa minimalidad y, luego, agregar los sistemas nuevamente de forma óptima.

En fin, cada uno tiene metas distintas y lo hará a su manera hasta lograrlo. Simplemente expongo mi forma de verlo que, quizá, a alguien más le pueda parecer razonable. Yo apunto a algo más general que simplemente tener un Season 6 sin drops de FPS sino que pretendo tener un código fuente mantenible, escalable, bien organizado y creo que partiendo de lo que dije es como se logra más rápidamente que refactorizando el source tal como está.

Dicho esto espero que todos logren lo que tengan propuesto y que la comunidad continúe avanzando para atraer más gente y que las nuevas generaciones puedan disfrutar como nosotros de esto 😊


Offline YolaxD #8 Posteado: August 06, 2025, 11:08:06 AM

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Puto amo
  • Posts: 543
  • Gracias recibida: 8598
  • ar
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}

Claro, entiendo perfectamente tu punto e incluso sé que se puede lograr sin necesidad de optar por un main bajo.

A lo que voy es que la arquitectura del software del juego no está pensada para ser escalada y todo se termina agregando con herramientas externas (los encoder para items, mapas, monstruos, efectos, etc.).

Entonces mi punto es, si ya se está optando por una buena refactorización del juego por qué no hacerla como corresponde optando por algo súper básico y volviendo a escalar añadiendo (COMO CORRESPONDE, NO COMO WEBZEN) cada sistema nuevamente de manera eficiente.
Como el ejemplo que di, el main 0.53 trae simplemente 3 personajes, 5 mapas, 16 items por categoría, sin evoluciones y sin eventos. Toda la lógica base para añadir el MG y el DL por ejemplo se pueden simplificar y unificar completamente en un sistema base donde agregar un personaje nuevo no requiera tocar diez millones de IF.

Ojo a esto, no me refiero a agregarlo por DLL sino a decompilar el main, tener un código compilable de un main muy reducido (la decompilación es más fácil guiándose con el source s5.2) y a partir de ahí trabajar en ese source pequeño y limpio.

Y ni hablemos de las sincronizaciones de datos. Montones de archivos podrían migrarse directamente a un sistema de solicitud hacia el servidor, aprovechando más el consumo de red que el consumo de cpu, optando por mejorar la sincronización con el servidor. (Ejemplos boludos: el chaos mix, los stats de la C, la información del viewport, el movelist, el listado de servidores del select server, etc.).

Creo yo que Webzen tiene un muy mal código integrado y que todas las funcionalidades fueron añadidas como se pudo simplemente para que funcionen y no se tuvo en cuenta que funcionen bien. Al menos yo considero que todos los mains tienen miles de problemas que se solucionan reescribiendo los sistemas de manera óptima.

Y por último, yo veo un aspecto un poco más amplio que sólo la Season 6. Entiendo que todos targeteen esa única versión y, a partir de ahí, quieran upgradear o downgradear. A mi parecer, es mucho más factible partir de algo súper nativo con sistemas muy simples, ya que refactorizar todo lo necesario sería mucho más sencillo teniendo poco código que manosear (el render es exactamente el mismo, nada más cambian tamaños de texturas y modelos un poco más complejos). Entonces una vez refactorizado algo nativo, se puede reescalar nuevamente y llevar a Season 6 o más, pero integrando cada sistema de manera óptima y refactorizada.
A lo que voy es que si mirás el código, más de la mitad está escrito de manera HORRENDA. Si tuvieras que refactorizar cada sistema uno por uno (las opciones de los items, los ancient, los harmony, los 380, los socket) qué te llevaría más? Agarrar una base limpia e ir agregándolos ya refactorizados o ir buscando dónde está cada sistema reescribiendo función por función, manteniendo la lógica pedorra de Webzen? Se entiende mi punto con esto?

Lo que propongo sería prácticamente reescribir el main nuevamente pero partiendo desde una base funcional mínima, en lugar de tener que refactorizar algo ya desorganizado y sin lógica de escalabilidad, ni buena arquitectura de software. Tampoco pretendo irme por las ramas como SirMaster, que planteó un proyecto remake escribiendo todo de 0 y, en todo el tiempo que invirtió no logró ni siquiera tener algo jugable. En este caso se parte de algo jugable pero mínimo y simplemente toca optimizar esa minimalidad y, luego, agregar los sistemas nuevamente de forma óptima.

En fin, cada uno tiene metas distintas y lo hará a su manera hasta lograrlo. Simplemente expongo mi forma de verlo que, quizá, a alguien más le pueda parecer razonable. Yo apunto a algo más general que simplemente tener un Season 6 sin drops de FPS sino que pretendo tener un código fuente mantenible, escalable, bien organizado y creo que partiendo de lo que dije es como se logra más rápidamente que refactorizando el source tal como está.

Dicho esto espero que todos logren lo que tengan propuesto y que la comunidad continúe avanzando para atraer más gente y que las nuevas generaciones puedan disfrutar como nosotros de esto 😊


la verdad no tiene sentido decompilar algo como el .54 para luego rescribir, tenes todo el el main S5, solo debes filtrar lo que no necesitas y empezar a escribir el codigo nuevo, realmente es una perdida de tiempo decompiar el .54, tiene sistemas que no te van a servir igual que el S5 y perderas el tiempo decompilado que puedes aprobechar para ver bien el funcionamiento en un codigo legible y sin tener que reinterpretar tanto, pero bueno cada uno tiene sus metodos y demas aunque yo en lo personal no le veo sentido, tambien deben de dejar de tenerle tanto miedo a esos switch y if anidados eso no es el mayor problema que tiene el juego , los compiladores actuales optimizan bastante al momento de compilar , no digo que no sea un problema pero no va a ser el causante de tener un bajon o subida de consumo drastica , uno de los mayores problemas que tiene es toda la gestion de memoria que no aproecha el cache del CPU por lo que podrian optar en analisar mejor eso y lo que dice el tipo de arriba sobre el terreno tambien es un punto clave :)


Offline takumi12 #9 Posteado: August 06, 2025, 04:43:09 PM

  • MAESTRO

  • US. DE HONOR

  • LEYENDA

  • Php Coder
  • +11 puntos por ventas
  • *
  • *
  • Rank: Puto amo
  • Posts: 1.048
  • Gracias recibida: 45436
  • mx
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}

Claro, entiendo perfectamente tu punto e incluso sé que se puede lograr sin necesidad de optar por un main bajo.

A lo que voy es que la arquitectura del software del juego no está pensada para ser escalada y todo se termina agregando con herramientas externas (los encoder para items, mapas, monstruos, efectos, etc.).

Entonces mi punto es, si ya se está optando por una buena refactorización del juego por qué no hacerla como corresponde optando por algo súper básico y volviendo a escalar añadiendo (COMO CORRESPONDE, NO COMO WEBZEN) cada sistema nuevamente de manera eficiente.
Como el ejemplo que di, el main 0.53 trae simplemente 3 personajes, 5 mapas, 16 items por categoría, sin evoluciones y sin eventos. Toda la lógica base para añadir el MG y el DL por ejemplo se pueden simplificar y unificar completamente en un sistema base donde agregar un personaje nuevo no requiera tocar diez millones de IF.

Ojo a esto, no me refiero a agregarlo por DLL sino a decompilar el main, tener un código compilable de un main muy reducido (la decompilación es más fácil guiándose con el source s5.2) y a partir de ahí trabajar en ese source pequeño y limpio.

Y ni hablemos de las sincronizaciones de datos. Montones de archivos podrían migrarse directamente a un sistema de solicitud hacia el servidor, aprovechando más el consumo de red que el consumo de cpu, optando por mejorar la sincronización con el servidor. (Ejemplos boludos: el chaos mix, los stats de la C, la información del viewport, el movelist, el listado de servidores del select server, etc.).

Creo yo que Webzen tiene un muy mal código integrado y que todas las funcionalidades fueron añadidas como se pudo simplemente para que funcionen y no se tuvo en cuenta que funcionen bien. Al menos yo considero que todos los mains tienen miles de problemas que se solucionan reescribiendo los sistemas de manera óptima.

Y por último, yo veo un aspecto un poco más amplio que sólo la Season 6. Entiendo que todos targeteen esa única versión y, a partir de ahí, quieran upgradear o downgradear. A mi parecer, es mucho más factible partir de algo súper nativo con sistemas muy simples, ya que refactorizar todo lo necesario sería mucho más sencillo teniendo poco código que manosear (el render es exactamente el mismo, nada más cambian tamaños de texturas y modelos un poco más complejos). Entonces una vez refactorizado algo nativo, se puede reescalar nuevamente y llevar a Season 6 o más, pero integrando cada sistema de manera óptima y refactorizada.
A lo que voy es que si mirás el código, más de la mitad está escrito de manera HORRENDA. Si tuvieras que refactorizar cada sistema uno por uno (las opciones de los items, los ancient, los harmony, los 380, los socket) qué te llevaría más? Agarrar una base limpia e ir agregándolos ya refactorizados o ir buscando dónde está cada sistema reescribiendo función por función, manteniendo la lógica pedorra de Webzen? Se entiende mi punto con esto?

Lo que propongo sería prácticamente reescribir el main nuevamente pero partiendo desde una base funcional mínima, en lugar de tener que refactorizar algo ya desorganizado y sin lógica de escalabilidad, ni buena arquitectura de software. Tampoco pretendo irme por las ramas como SirMaster, que planteó un proyecto remake escribiendo todo de 0 y, en todo el tiempo que invirtió no logró ni siquiera tener algo jugable. En este caso se parte de algo jugable pero mínimo y simplemente toca optimizar esa minimalidad y, luego, agregar los sistemas nuevamente de forma óptima.

En fin, cada uno tiene metas distintas y lo hará a su manera hasta lograrlo. Simplemente expongo mi forma de verlo que, quizá, a alguien más le pueda parecer razonable. Yo apunto a algo más general que simplemente tener un Season 6 sin drops de FPS sino que pretendo tener un código fuente mantenible, escalable, bien organizado y creo que partiendo de lo que dije es como se logra más rápidamente que refactorizando el source tal como está.

Dicho esto espero que todos logren lo que tengan propuesto y que la comunidad continúe avanzando para atraer más gente y que las nuevas generaciones puedan disfrutar como nosotros de esto 😊


la verdad no tiene sentido decompilar algo como el .54 para luego rescribir, tenes todo el el main S5, solo debes filtrar lo que no necesitas y empezar a escribir el codigo nuevo, realmente es una perdida de tiempo decompiar el .54, tiene sistemas que no te van a servir igual que el S5 y perderas el tiempo decompilado que puedes aprobechar para ver bien el funcionamiento en un codigo legible y sin tener que reinterpretar tanto, pero bueno cada uno tiene sus metodos y demas aunque yo en lo personal no le veo sentido, tambien deben de dejar de tenerle tanto miedo a esos switch y if anidados eso no es el mayor problema que tiene el juego , los compiladores actuales optimizan bastante al momento de compilar , no digo que no sea un problema pero no va a ser el causante de tener un bajon o subida de consumo drastica , uno de los mayores problemas que tiene es toda la gestion de memoria que no aproecha el cache del CPU por lo que podrian optar en analisar mejor eso y lo que dice el tipo de arriba sobre el terreno tambien es un punto clave :)

eso es parte de la verdad, cuando dejas de ver a mu online como mu online, y comienzas a expandir el campo de estructura en pensar como se formaría siendo un engine, ni si quiera necesitas reconstruir, basta con organizar y por si solo se irá adaptando a un modo de juego moderno temprano:

modelo escalable de reestructuracion:
Code: [Select]
/EngineRoot
    /src
        /Core             <- Sistema base: logs, utilidades, memory, etc.
        /Graphics         <- Renderer, recursos, texturas, shaders, materiales
        /Scene            <- Objetos, entidades, transformaciones, culling
        /Game             <- Lógica específica del juego, reglas, mods, eventos
        /UI               <- Sistema de UI/HUD/menus
        /Input            <- Teclado, mouse, gamepad, bindings
        /Audio            <- (Opcional) Manejo de sonido/música
        /Platform         <- Adaptación a Windows/Linux, paths, archivos, ventanas
        /Tools            <- Herramientas internas (editores, converters, exporters)
    /assets
        /models
        /textures
        /sounds
    /shaders
    /include
    /cmake
    main.cpp
    CMakeLists.txt

ahora planteando la estrategia de menjar algo mas sofisticado

Code: [Select]
#pragma once

class SceneInstance
{
public:
virtual ~SceneInstance() = default;

virtual int GetID() const = 0;

// Inicialización de la escena (carga recursos, setup)
virtual void Init() = 0;

// Liberación de recursos
virtual void Cleanup() = 0;

// Se llama cada frame para actualizar la lógica de la escena
virtual void Update(float deltaTime) = 0;

// Se llama cada frame para renderizar la escena
virtual void Render() = 0;

// Eventos de entrada, si quieres procesarlos aquí
virtual void OnInput(/* ... */) { /* Opcional */ }
};

class SceneManager
{
public:
// Cambia a una nueva escena (descarta la actual)
void ChangeScene(std::unique_ptr<SceneInstance> newScene);

// Pone una nueva escena sobre la actual (stack)
void PushScene(std::unique_ptr<SceneInstance> scene);

// Quita la escena actual y vuelve a la anterior
void PopScene();

// Llama al update/render de la escena activa
void Update(float deltaTime);
void Render();

// Acceso a la escena actual
void SetFlag(int flag);
int GetCurrentflag();
SceneInstance* GetCurrentScene();
static SceneManager* Instance();
private:
std::stack<std::unique_ptr<SceneInstance>> sceneStack;
};

#define gSceneManager (SceneManager::Instance())

Code: [Select]
void SceneManager::ChangeScene(std::unique_ptr<SceneInstance> newScene)
{
// Limpia y elimina la escena actual
if (!sceneStack.empty())
{
sceneStack.top()->Cleanup();
sceneStack.pop();

g_ConsoleDebug->Write(5, "sacando scene");
}
// Inicializa y agrega la nueva escena
newScene->Init();
sceneStack.push(std::move(newScene));
}

void SceneManager::PushScene(std::unique_ptr<SceneInstance> scene)
{
scene->Init();
sceneStack.push(std::move(scene));
}

void SceneManager::PopScene()
{
if (!sceneStack.empty())
{
sceneStack.top()->Cleanup();
sceneStack.pop();
}
}

void SceneManager::Update(float deltaTime)
{
if (!sceneStack.empty())
{
sceneStack.top()->Update(deltaTime);
}
}

void SceneManager::Render()
{
if (!sceneStack.empty())
{
sceneStack.top()->Render();
}
}

void SceneManager::SetFlag(int flag)
{
if (gSceneManager->GetCurrentflag() != flag)
{
switch (flag)
{
case WEBZEN_SCENE:
this->ChangeScene(std::make_unique<SceneLoading>());
break;
//case LOADING_SCENE:
// this->ChangeScene(std::make_unique<SceneLogin>());
// break;
case LOG_IN_SCENE:
this->ChangeScene(std::make_unique<SceneLogin>());
break;
case CHARACTER_SCENE:
this->ChangeScene(std::make_unique<SceneCharacter>());
break;
//case MAIN_SCENE:
// this->ChangeScene(std::make_unique<SceneCharacter>());
// break;
}
}
}

int SceneManager::GetCurrentflag()
{
return sceneStack.empty() ? NON_SCENE : sceneStack.top()->GetID();
}

SceneInstance* SceneManager::GetCurrentScene()
{
return sceneStack.empty() ? nullptr : sceneStack.top().get();
}

SceneManager* SceneManager::Instance()
{
static SceneManager s_Instance;
return &s_Instance;
}

uno de los primeros problemas es la gestion de memoria sincronizada, y parcial, otra cosa que se tiene que reestructurar si o si, es el frustrum que en palabras de programacion para juego se le llama frustrum, eso también llega a causar que el problema de carga para el terreno plano sea costoso, que se puede hacer?


Code: [Select]
void MUCullingFace::Frustum3DPlanes(vec3_t position)
{
float proj[16];
float clip[16];
float modelview[16];

glGetFloatv(GL_PROJECTION_MATRIX, proj);
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);

// Multiplicacion OpenGL: clip = proj * modelview
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
clip[i + j * 4] =
modelview[0 + j * 4] * proj[i + 0] +
modelview[1 + j * 4] * proj[i + 4] +
modelview[2 + j * 4] * proj[i + 8] +
modelview[3 + j * 4] * proj[i + 12];
}
}

// Extract and normalize planes
auto normalize = [](float* p) {
float length = sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
if (length > 0.0f) {
p[0] /= length; p[1] /= length; p[2] /= length; p[3] /= length;
}
};

// Left
fFrustumPlane[0][0] = clip[3] + clip[0];
fFrustumPlane[0][1] = clip[7] + clip[4];
fFrustumPlane[0][2] = clip[11] + clip[8];
fFrustumPlane[0][3] = clip[15] + clip[12];
normalize(fFrustumPlane[0]);

// Right
fFrustumPlane[1][0] = clip[3] - clip[0];
fFrustumPlane[1][1] = clip[7] - clip[4];
fFrustumPlane[1][2] = clip[11] - clip[8];
fFrustumPlane[1][3] = clip[15] - clip[12];
normalize(fFrustumPlane[1]);

// Bottom
fFrustumPlane[2][0] = clip[3] + clip[1];
fFrustumPlane[2][1] = clip[7] + clip[5];
fFrustumPlane[2][2] = clip[11] + clip[9];
fFrustumPlane[2][3] = clip[15] + clip[13];
normalize(fFrustumPlane[2]);

// Top
fFrustumPlane[3][0] = clip[3] - clip[1];
fFrustumPlane[3][1] = clip[7] - clip[5];
fFrustumPlane[3][2] = clip[11] - clip[9];
fFrustumPlane[3][3] = clip[15] - clip[13];
normalize(fFrustumPlane[3]);

// Near
fFrustumPlane[4][0] = clip[3] + clip[2];
fFrustumPlane[4][1] = clip[7] + clip[6];
fFrustumPlane[4][2] = clip[11] + clip[10];
fFrustumPlane[4][3] = clip[15] + clip[14];
normalize(fFrustumPlane[4]);

// Far
fFrustumPlane[5][0] = clip[3] - clip[2];
fFrustumPlane[5][1] = clip[7] - clip[6];
fFrustumPlane[5][2] = clip[11] - clip[10];
fFrustumPlane[5][3] = clip[15] - clip[14];

normalize(fFrustumPlane[5]);
}

muchas de las cosas que se tienen que re estructurar no entra la logica del juego, si no la implementacion de como esta planteado el manejo y control de los callback de opengl y las limitaciones que se realizan en la expansion de uso en la camara


Las offset no se crea, ni se destruye, solo se transforma

Gracias:


Offline Feche #10 Posteado: August 07, 2025, 10:57:51 PM | Modificado: August 07, 2025, 11:00:35 PM by Feche

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Dedicado
  • Posts: 50
  • Gracias recibida: 1509
  • ar
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}

Claro, entiendo perfectamente tu punto e incluso sé que se puede lograr sin necesidad de optar por un main bajo.

A lo que voy es que la arquitectura del software del juego no está pensada para ser escalada y todo se termina agregando con herramientas externas (los encoder para items, mapas, monstruos, efectos, etc.).

Entonces mi punto es, si ya se está optando por una buena refactorización del juego por qué no hacerla como corresponde optando por algo súper básico y volviendo a escalar añadiendo (COMO CORRESPONDE, NO COMO WEBZEN) cada sistema nuevamente de manera eficiente.
Como el ejemplo que di, el main 0.53 trae simplemente 3 personajes, 5 mapas, 16 items por categoría, sin evoluciones y sin eventos. Toda la lógica base para añadir el MG y el DL por ejemplo se pueden simplificar y unificar completamente en un sistema base donde agregar un personaje nuevo no requiera tocar diez millones de IF.

Ojo a esto, no me refiero a agregarlo por DLL sino a decompilar el main, tener un código compilable de un main muy reducido (la decompilación es más fácil guiándose con el source s5.2) y a partir de ahí trabajar en ese source pequeño y limpio.

Y ni hablemos de las sincronizaciones de datos. Montones de archivos podrían migrarse directamente a un sistema de solicitud hacia el servidor, aprovechando más el consumo de red que el consumo de cpu, optando por mejorar la sincronización con el servidor. (Ejemplos boludos: el chaos mix, los stats de la C, la información del viewport, el movelist, el listado de servidores del select server, etc.).

Creo yo que Webzen tiene un muy mal código integrado y que todas las funcionalidades fueron añadidas como se pudo simplemente para que funcionen y no se tuvo en cuenta que funcionen bien. Al menos yo considero que todos los mains tienen miles de problemas que se solucionan reescribiendo los sistemas de manera óptima.

Y por último, yo veo un aspecto un poco más amplio que sólo la Season 6. Entiendo que todos targeteen esa única versión y, a partir de ahí, quieran upgradear o downgradear. A mi parecer, es mucho más factible partir de algo súper nativo con sistemas muy simples, ya que refactorizar todo lo necesario sería mucho más sencillo teniendo poco código que manosear (el render es exactamente el mismo, nada más cambian tamaños de texturas y modelos un poco más complejos). Entonces una vez refactorizado algo nativo, se puede reescalar nuevamente y llevar a Season 6 o más, pero integrando cada sistema de manera óptima y refactorizada.
A lo que voy es que si mirás el código, más de la mitad está escrito de manera HORRENDA. Si tuvieras que refactorizar cada sistema uno por uno (las opciones de los items, los ancient, los harmony, los 380, los socket) qué te llevaría más? Agarrar una base limpia e ir agregándolos ya refactorizados o ir buscando dónde está cada sistema reescribiendo función por función, manteniendo la lógica pedorra de Webzen? Se entiende mi punto con esto?

Lo que propongo sería prácticamente reescribir el main nuevamente pero partiendo desde una base funcional mínima, en lugar de tener que refactorizar algo ya desorganizado y sin lógica de escalabilidad, ni buena arquitectura de software. Tampoco pretendo irme por las ramas como SirMaster, que planteó un proyecto remake escribiendo todo de 0 y, en todo el tiempo que invirtió no logró ni siquiera tener algo jugable. En este caso se parte de algo jugable pero mínimo y simplemente toca optimizar esa minimalidad y, luego, agregar los sistemas nuevamente de forma óptima.

En fin, cada uno tiene metas distintas y lo hará a su manera hasta lograrlo. Simplemente expongo mi forma de verlo que, quizá, a alguien más le pueda parecer razonable. Yo apunto a algo más general que simplemente tener un Season 6 sin drops de FPS sino que pretendo tener un código fuente mantenible, escalable, bien organizado y creo que partiendo de lo que dije es como se logra más rápidamente que refactorizando el source tal como está.

Dicho esto espero que todos logren lo que tengan propuesto y que la comunidad continúe avanzando para atraer más gente y que las nuevas generaciones puedan disfrutar como nosotros de esto 😊


la verdad no tiene sentido decompilar algo como el .54 para luego rescribir, tenes todo el el main S5, solo debes filtrar lo que no necesitas y empezar a escribir el codigo nuevo, realmente es una perdida de tiempo decompiar el .54, tiene sistemas que no te van a servir igual que el S5 y perderas el tiempo decompilado que puedes aprobechar para ver bien el funcionamiento en un codigo legible y sin tener que reinterpretar tanto, pero bueno cada uno tiene sus metodos y demas aunque yo en lo personal no le veo sentido, tambien deben de dejar de tenerle tanto miedo a esos switch y if anidados eso no es el mayor problema que tiene el juego , los compiladores actuales optimizan bastante al momento de compilar , no digo que no sea un problema pero no va a ser el causante de tener un bajon o subida de consumo drastica , uno de los mayores problemas que tiene es toda la gestion de memoria que no aproecha el cache del CPU por lo que podrian optar en analisar mejor eso y lo que dice el tipo de arriba sobre el terreno tambien es un punto clave :)

eso es parte de la verdad, cuando dejas de ver a mu online como mu online, y comienzas a expandir el campo de estructura en pensar como se formaría siendo un engine, ni si quiera necesitas reconstruir, basta con organizar y por si solo se irá adaptando a un modo de juego moderno temprano:

modelo escalable de reestructuracion:
Code: [Select]
/EngineRoot
    /src
        /Core             <- Sistema base: logs, utilidades, memory, etc.
        /Graphics         <- Renderer, recursos, texturas, shaders, materiales
        /Scene            <- Objetos, entidades, transformaciones, culling
        /Game             <- Lógica específica del juego, reglas, mods, eventos
        /UI               <- Sistema de UI/HUD/menus
        /Input            <- Teclado, mouse, gamepad, bindings
        /Audio            <- (Opcional) Manejo de sonido/música
        /Platform         <- Adaptación a Windows/Linux, paths, archivos, ventanas
        /Tools            <- Herramientas internas (editores, converters, exporters)
    /assets
        /models
        /textures
        /sounds
    /shaders
    /include
    /cmake
    main.cpp
    CMakeLists.txt

ahora planteando la estrategia de menjar algo mas sofisticado

Code: [Select]
#pragma once

class SceneInstance
{
public:
virtual ~SceneInstance() = default;

virtual int GetID() const = 0;

// Inicialización de la escena (carga recursos, setup)
virtual void Init() = 0;

// Liberación de recursos
virtual void Cleanup() = 0;

// Se llama cada frame para actualizar la lógica de la escena
virtual void Update(float deltaTime) = 0;

// Se llama cada frame para renderizar la escena
virtual void Render() = 0;

// Eventos de entrada, si quieres procesarlos aquí
virtual void OnInput(/* ... */) { /* Opcional */ }
};

class SceneManager
{
public:
// Cambia a una nueva escena (descarta la actual)
void ChangeScene(std::unique_ptr<SceneInstance> newScene);

// Pone una nueva escena sobre la actual (stack)
void PushScene(std::unique_ptr<SceneInstance> scene);

// Quita la escena actual y vuelve a la anterior
void PopScene();

// Llama al update/render de la escena activa
void Update(float deltaTime);
void Render();

// Acceso a la escena actual
void SetFlag(int flag);
int GetCurrentflag();
SceneInstance* GetCurrentScene();
static SceneManager* Instance();
private:
std::stack<std::unique_ptr<SceneInstance>> sceneStack;
};

#define gSceneManager (SceneManager::Instance())

Code: [Select]
void SceneManager::ChangeScene(std::unique_ptr<SceneInstance> newScene)
{
// Limpia y elimina la escena actual
if (!sceneStack.empty())
{
sceneStack.top()->Cleanup();
sceneStack.pop();

g_ConsoleDebug->Write(5, "sacando scene");
}
// Inicializa y agrega la nueva escena
newScene->Init();
sceneStack.push(std::move(newScene));
}

void SceneManager::PushScene(std::unique_ptr<SceneInstance> scene)
{
scene->Init();
sceneStack.push(std::move(scene));
}

void SceneManager::PopScene()
{
if (!sceneStack.empty())
{
sceneStack.top()->Cleanup();
sceneStack.pop();
}
}

void SceneManager::Update(float deltaTime)
{
if (!sceneStack.empty())
{
sceneStack.top()->Update(deltaTime);
}
}

void SceneManager::Render()
{
if (!sceneStack.empty())
{
sceneStack.top()->Render();
}
}

void SceneManager::SetFlag(int flag)
{
if (gSceneManager->GetCurrentflag() != flag)
{
switch (flag)
{
case WEBZEN_SCENE:
this->ChangeScene(std::make_unique<SceneLoading>());
break;
//case LOADING_SCENE:
// this->ChangeScene(std::make_unique<SceneLogin>());
// break;
case LOG_IN_SCENE:
this->ChangeScene(std::make_unique<SceneLogin>());
break;
case CHARACTER_SCENE:
this->ChangeScene(std::make_unique<SceneCharacter>());
break;
//case MAIN_SCENE:
// this->ChangeScene(std::make_unique<SceneCharacter>());
// break;
}
}
}

int SceneManager::GetCurrentflag()
{
return sceneStack.empty() ? NON_SCENE : sceneStack.top()->GetID();
}

SceneInstance* SceneManager::GetCurrentScene()
{
return sceneStack.empty() ? nullptr : sceneStack.top().get();
}

SceneManager* SceneManager::Instance()
{
static SceneManager s_Instance;
return &s_Instance;
}

uno de los primeros problemas es la gestion de memoria sincronizada, y parcial, otra cosa que se tiene que reestructurar si o si, es el frustrum que en palabras de programacion para juego se le llama frustrum, eso también llega a causar que el problema de carga para el terreno plano sea costoso, que se puede hacer?


Code: [Select]
void MUCullingFace::Frustum3DPlanes(vec3_t position)
{
float proj[16];
float clip[16];
float modelview[16];

glGetFloatv(GL_PROJECTION_MATRIX, proj);
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);

// Multiplicacion OpenGL: clip = proj * modelview
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
clip[i + j * 4] =
modelview[0 + j * 4] * proj[i + 0] +
modelview[1 + j * 4] * proj[i + 4] +
modelview[2 + j * 4] * proj[i + 8] +
modelview[3 + j * 4] * proj[i + 12];
}
}

// Extract and normalize planes
auto normalize = [](float* p) {
float length = sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
if (length > 0.0f) {
p[0] /= length; p[1] /= length; p[2] /= length; p[3] /= length;
}
};

// Left
fFrustumPlane[0][0] = clip[3] + clip[0];
fFrustumPlane[0][1] = clip[7] + clip[4];
fFrustumPlane[0][2] = clip[11] + clip[8];
fFrustumPlane[0][3] = clip[15] + clip[12];
normalize(fFrustumPlane[0]);

// Right
fFrustumPlane[1][0] = clip[3] - clip[0];
fFrustumPlane[1][1] = clip[7] - clip[4];
fFrustumPlane[1][2] = clip[11] - clip[8];
fFrustumPlane[1][3] = clip[15] - clip[12];
normalize(fFrustumPlane[1]);

// Bottom
fFrustumPlane[2][0] = clip[3] + clip[1];
fFrustumPlane[2][1] = clip[7] + clip[5];
fFrustumPlane[2][2] = clip[11] + clip[9];
fFrustumPlane[2][3] = clip[15] + clip[13];
normalize(fFrustumPlane[2]);

// Top
fFrustumPlane[3][0] = clip[3] - clip[1];
fFrustumPlane[3][1] = clip[7] - clip[5];
fFrustumPlane[3][2] = clip[11] - clip[9];
fFrustumPlane[3][3] = clip[15] - clip[13];
normalize(fFrustumPlane[3]);

// Near
fFrustumPlane[4][0] = clip[3] + clip[2];
fFrustumPlane[4][1] = clip[7] + clip[6];
fFrustumPlane[4][2] = clip[11] + clip[10];
fFrustumPlane[4][3] = clip[15] + clip[14];
normalize(fFrustumPlane[4]);

// Far
fFrustumPlane[5][0] = clip[3] - clip[2];
fFrustumPlane[5][1] = clip[7] - clip[6];
fFrustumPlane[5][2] = clip[11] - clip[10];
fFrustumPlane[5][3] = clip[15] - clip[14];

normalize(fFrustumPlane[5]);
}

muchas de las cosas que se tienen que re estructurar no entra la logica del juego, si no la implementacion de como esta planteado el manejo y control de los callback de opengl y las limitaciones que se realizan en la expansion de uso en la camara

Para realmente modernizar, se saca completamente el model view y se usa una proyeccion con camara:

u_projectionMatrix * u_viewMatrix * u_modelMatrix

El juego en si utiliza 2 chequeaos para renderizar el terreno:
1: Escanea el primer 'frustum' (si, entre comillas porque no es el verdadero frustrum) que es cuadrado y formado por CameraFOV, CameraViewNear y CameraViewFar
2: Si esta dentro del primer 'frustrum', escanea el segundo frustrum (este si es el verdadero, es el que renderiza tu pantalla) y si esta dentro entonces renderiza el terreno

Para optimizar el renderizado del terreno, se deberia renderizar en chunks y/o utilizar VAO/VBO/EBO, pero para estas funciones ya nesecitas OpenGL 2.0 como minimo.
Con VAOs puedo renderizar el terreno completo (256 * 256) a 60 fps - estoy porteando la version 97d a OGL 2.0.

Gracias:


Offline kayito #11 Posteado: August 08, 2025, 07:54:21 AM

  • MAESTRO

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Puto amo
  • Posts: 1.083
  • Gracias recibida: 19865
  • ar
Para realmente modernizar, se saca completamente el model view y se usa una proyeccion con camara:

u_projectionMatrix * u_viewMatrix * u_modelMatrix

El juego en si utiliza 2 chequeaos para renderizar el terreno:
1: Escanea el primer 'frustum' (si, entre comillas porque no es el verdadero frustrum) que es cuadrado y formado por CameraFOV, CameraViewNear y CameraViewFar
2: Si esta dentro del primer 'frustrum', escanea el segundo frustrum (este si es el verdadero, es el que renderiza tu pantalla) y si esta dentro entonces renderiza el terreno

Para optimizar el renderizado del terreno, se deberia renderizar en chunks y/o utilizar VAO/VBO/EBO, pero para estas funciones ya nesecitas OpenGL 2.0 como minimo.
Con VAOs puedo renderizar el terreno completo (256 * 256) a 60 fps - estoy porteando la version 97d a OGL 2.0.

Puedes usar Glew para actualizar Opengl hookeando la función que inicializa el contexto y guardando los valores en las direcciones de memoria originales del main.

Gracias:


Offline TranLam.Noria #12 Posteado: August 08, 2025, 08:35:36 AM

  • 0 puntos por ventas
  • *
  • Rank: Principiante
  • Posts: 7
  • Gracias recibida: 25
Buena la iniciativa. Es algo que tenía pensado incursionar, ponerme a estudiar y tratar de acomodar de base pero lamentablemente entre trabajo y estudio se hace imposible encontrar tiempo libre para hacerlo.

Como bien dice takumi, no alcanza únicamente con migrar el sistema a shaders y/o actualizar la api gráfica de versión, sino que hace falta optimizar muchas secuencias de código que trabajan de manera ineficiente, generando consumo innecesario.

Ante un proyecto de estas características, es complicado optar por pulir algo tan trabajado y con tantos sistemas integrados. El simple hecho de pensar en refactorizar ciertos sistemas te genera un dolor de cabeza. A mi parecer, lo ideal sería apuntar por un main mucho más liviano (por ejemplo el 0.53), decompilarlo y trabajar no sólo el render base sino también los subsistemas que se fueron integrando a medida que las temporadas fueron avanzando.
Tengamos en cuenta que el proyecto no estuvo muy bien diseñado para ser escalable y todo lo que fueron integrando básicamente fue pisar sobre sistemas funcionales o extenderlos, haciendo que la arquitectura del software no sea óptima y todo el proceso de ejecución de cada gameloop sea muy ineficiente.
Para corroborar lo que digo, basta con echarle una mirada a los switch case enormes que se pueden encontrar, los if else anidados e incluso algunas estructuras de datos utilizadas para manipular cantidades de datos (por ejemplo el sistema de efectos, el sistema de partículas, el sistema de texturas, etc.).

Yo creo que hoy día haciendo uso de las herramientas de IA que tenemos disponibles, intentando refactorizar sistema por sistema y modernizando no sólo la api gráfica sino también el propio código c++ y las estructuras utilizadas, podríamos llegar a tener un main como la gente.

En fin, espero que pronto vayamos viendo mejoras a nivel general para todos los emuladores.

creeme no es necesario volver a un main mas viejo para que sea optimo, solo es aplicar ciertas tecnigas eficientes de engines modernos, y sin necesidad de reescribir todos los sistemas se vuelve muy liviano, ahora si reescribes los sistemas a algo mas eficiente, uff, ese main de 16 bits te va bien hasta en una pc del 2006, ya que si cargas objetos originales del season6 no escalan a texturas mas grandes que 1024, y en su mayoria viene con texturas tan pequeñas de 256 pixles, como también los mesh no tienen huesos grandes, o vertices muy grandes como juegos modernos, lo que afecta mucho el rendimiento es el uso instantaneo de renderizado, por eso solo con aplicar shader no basta, porque sigues haciendo lo mismo de usar cpu para almacenar, y cargar al gpu en cada frame, que es exactamente lo que causa el problema de bajo rendimiento, existe un cuello de botella y es en el render principal, ahora es bonito pensar que se puede refactorizar o apuntar a crear un main de baja version porque es "mas eficiente", pero la realidad lo unico bueno de eso es que reinicias todos los sistemas a tu manera migrando poco a poco, pero si atacas directamente el tema de renderizar de manera instantanea, resuelves el problema de cuello de botella, y te queda un juego muy liviano comparado vs el main.exe season6 original, que puedes escalar a versiones altas, o bajar a versiones bajas, sin pedos, incluso aplicar todo lo que te digo en una main.dll es posible, hice algunas pruebas, y el rendimiento es abismal, pero al tener que tocas muchas offset no es viable hacerlo para emuladores ajenos, por ejemplo no podria crear una libreria .dll que funcione en mu emu louis, o emulador de zeta, o x, tendria que ser necesario implementarlo directo en main.dll hay muchas cosas que mejoran sin reescribir todo, el problema es aplicarlo de la manera adecuada


Code: [Select]
void CWINHANDLE::OFFSET__fixactiontarget()
{
SetByte(0x00813BF1 + 3, (0x01)); //-- fixed skill tooltip
SetByte(0x004EBD01 + 6, (0x01)); //-- Fix Tooltip Ancient
SetDword(0x0075366A + 3, (0xA)); //-- fixed skill darklord

SetCompleteHook(0xE8, 0x004D6EAA, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D7791, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x004D957C, &MoveCharactersClient);
SetCompleteHook(0xE8, 0x0055AFB8, &AddObjectDescription);
SetCompleteHook(0xE8, 0x004D9C8B, &RenderObjectDescription);
}

void CWINHANDLE::OFFSET__animationplaymodel()
{
SetCompleteHook(0xE8, 0x004F0356, FuncToDWORD(&BMD::AnimationPlayModel)); // CSParts::IRender
SetCompleteHook(0xE8, 0x004F05E0, FuncToDWORD(&BMD::AnimationPlayModel)); // CSAnimationParts::Animation
//SetCompleteHook(0xE8, 0x004F1079, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505D07, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00505ED4, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00507285, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0056653D, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005EF3CE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x005FCEB3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x006F53C8, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00700FFA, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701279, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00701302, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007058BF, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007077A3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007079EB, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00707BB0, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00713A89, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0071EAC2, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720749, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x007209C3, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x00720BAE, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072214E, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0072491C, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0074749A, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008E77C5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F0DC5, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F4F25, FuncToDWORD(&BMD::AnimationPlayModel));
//SetCompleteHook(0xE8, 0x008F9C95, FuncToDWORD(&BMD::AnimationPlayModel));
SetCompleteHook(0xE8, 0x0092AE37, FuncToDWORD(&BMD::AnimationPlayModel));
}

void CWINHANDLE::OFFSET__playmovephysics()
{
SetCompleteHook(0xE8, 0x0051E75C, FuncToDWORD(&CPhysicsVertex::Move));
SetCompleteHook(0xE9, 0x0051CB20, FuncToDWORD(&CPhysicsVertex::AddToForce));
SetCompleteHook(0xE9, 0x0051C890, FuncToDWORD(&CPhysicsVertex::UpdateForce));
SetCompleteHook(0xE9, 0x0051CF10, FuncToDWORD(&CPhysicsVertex::DoOneTimeMove));
SetCompleteHook(0xE9, 0x0051CFE0, FuncToDWORD(&CPhysicsVertex::AddOneTimeMove));

SetCompleteHook(0xE9, 0x0051E440, FuncToDWORD(&CPhysicsCloth::InitForces));
SetCompleteHook(0xE8, 0x0051E29D, FuncToDWORD(&CPhysicsCloth::Move));
SetCompleteHook(0xE8, 0x0051FED4, FuncToDWORD(&CPhysicsCloth::Move));
}


void CWINHANDLE::Initialize()
{
CWINHANDLE::OFFSET__createjoint();

CWINHANDLE::OFFSET__createeffect();

CWINHANDLE::OFFSET__createparticle();

CWINHANDLE::OFFSET__fixactiontarget();

CWINHANDLE::OFFSET__renderNormalizer();

CWINHANDLE::OFFSET__animationplaymodel();

CWINHANDLE::OFFSET__playmovephysics();

SetCompleteHook(0xE8, 0x005DA43A, &RenderTerrainFace);
SetCompleteHook(0xE8, 0x00860B1D, &OPENGL32__AlphaFunc204);
SetCompleteHook(0xE8, 0x00860B37, &OPENGL32__AlphaFunc205);

SetCompleteHook(0xE9, 0x00547537, &RENDERMESH_INTELLIGEN);
SetCompleteHook(0xE9, 0x004DA3A1, &MAIN_SCENE_THREAD_LOOP);
SetCompleteHook(0xE9, 0x004DE9AF, &LOGINSCENE_CAMERA_MOVE);
SetCompleteHook(0xE9, 0x004DE7CB, &LOGINSCENE_CAMERA_ROTATE);

SetCompleteHook(0xE8, 0x004D9D13, &CWINHANDLE::CalcFPS);
SetCompleteHook(0xE8, 0x004D2103, &CWINHANDLE::OpenMainExe);
SetCompleteHook(0xE8, 0x004CF56C, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D04BA, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x0077255E, &CWINHANDLE::CloseMainExe);
SetCompleteHook(0xE8, 0x004D9F2A, &CWINHANDLE::Set3DSoundPosition);
}

Claro, entiendo perfectamente tu punto e incluso sé que se puede lograr sin necesidad de optar por un main bajo.

A lo que voy es que la arquitectura del software del juego no está pensada para ser escalada y todo se termina agregando con herramientas externas (los encoder para items, mapas, monstruos, efectos, etc.).

Entonces mi punto es, si ya se está optando por una buena refactorización del juego por qué no hacerla como corresponde optando por algo súper básico y volviendo a escalar añadiendo (COMO CORRESPONDE, NO COMO WEBZEN) cada sistema nuevamente de manera eficiente.
Como el ejemplo que di, el main 0.53 trae simplemente 3 personajes, 5 mapas, 16 items por categoría, sin evoluciones y sin eventos. Toda la lógica base para añadir el MG y el DL por ejemplo se pueden simplificar y unificar completamente en un sistema base donde agregar un personaje nuevo no requiera tocar diez millones de IF.

Ojo a esto, no me refiero a agregarlo por DLL sino a decompilar el main, tener un código compilable de un main muy reducido (la decompilación es más fácil guiándose con el source s5.2) y a partir de ahí trabajar en ese source pequeño y limpio.

Y ni hablemos de las sincronizaciones de datos. Montones de archivos podrían migrarse directamente a un sistema de solicitud hacia el servidor, aprovechando más el consumo de red que el consumo de cpu, optando por mejorar la sincronización con el servidor. (Ejemplos boludos: el chaos mix, los stats de la C, la información del viewport, el movelist, el listado de servidores del select server, etc.).

Creo yo que Webzen tiene un muy mal código integrado y que todas las funcionalidades fueron añadidas como se pudo simplemente para que funcionen y no se tuvo en cuenta que funcionen bien. Al menos yo considero que todos los mains tienen miles de problemas que se solucionan reescribiendo los sistemas de manera óptima.

Y por último, yo veo un aspecto un poco más amplio que sólo la Season 6. Entiendo que todos targeteen esa única versión y, a partir de ahí, quieran upgradear o downgradear. A mi parecer, es mucho más factible partir de algo súper nativo con sistemas muy simples, ya que refactorizar todo lo necesario sería mucho más sencillo teniendo poco código que manosear (el render es exactamente el mismo, nada más cambian tamaños de texturas y modelos un poco más complejos). Entonces una vez refactorizado algo nativo, se puede reescalar nuevamente y llevar a Season 6 o más, pero integrando cada sistema de manera óptima y refactorizada.
A lo que voy es que si mirás el código, más de la mitad está escrito de manera HORRENDA. Si tuvieras que refactorizar cada sistema uno por uno (las opciones de los items, los ancient, los harmony, los 380, los socket) qué te llevaría más? Agarrar una base limpia e ir agregándolos ya refactorizados o ir buscando dónde está cada sistema reescribiendo función por función, manteniendo la lógica pedorra de Webzen? Se entiende mi punto con esto?

Lo que propongo sería prácticamente reescribir el main nuevamente pero partiendo desde una base funcional mínima, en lugar de tener que refactorizar algo ya desorganizado y sin lógica de escalabilidad, ni buena arquitectura de software. Tampoco pretendo irme por las ramas como SirMaster, que planteó un proyecto remake escribiendo todo de 0 y, en todo el tiempo que invirtió no logró ni siquiera tener algo jugable. En este caso se parte de algo jugable pero mínimo y simplemente toca optimizar esa minimalidad y, luego, agregar los sistemas nuevamente de forma óptima.

En fin, cada uno tiene metas distintas y lo hará a su manera hasta lograrlo. Simplemente expongo mi forma de verlo que, quizá, a alguien más le pueda parecer razonable. Yo apunto a algo más general que simplemente tener un Season 6 sin drops de FPS sino que pretendo tener un código fuente mantenible, escalable, bien organizado y creo que partiendo de lo que dije es como se logra más rápidamente que refactorizando el source tal como está.

Dicho esto espero que todos logren lo que tengan propuesto y que la comunidad continúe avanzando para atraer más gente y que las nuevas generaciones puedan disfrutar como nosotros de esto 😊


la verdad no tiene sentido decompilar algo como el .54 para luego rescribir, tenes todo el el main S5, solo debes filtrar lo que no necesitas y empezar a escribir el codigo nuevo, realmente es una perdida de tiempo decompiar el .54, tiene sistemas que no te van a servir igual que el S5 y perderas el tiempo decompilado que puedes aprobechar para ver bien el funcionamiento en un codigo legible y sin tener que reinterpretar tanto, pero bueno cada uno tiene sus metodos y demas aunque yo en lo personal no le veo sentido, tambien deben de dejar de tenerle tanto miedo a esos switch y if anidados eso no es el mayor problema que tiene el juego , los compiladores actuales optimizan bastante al momento de compilar , no digo que no sea un problema pero no va a ser el causante de tener un bajon o subida de consumo drastica , uno de los mayores problemas que tiene es toda la gestion de memoria que no aproecha el cache del CPU por lo que podrian optar en analisar mejor eso y lo que dice el tipo de arriba sobre el terreno tambien es un punto clave :)

eso es parte de la verdad, cuando dejas de ver a mu online como mu online, y comienzas a expandir el campo de estructura en pensar como se formaría siendo un engine, ni si quiera necesitas reconstruir, basta con organizar y por si solo se irá adaptando a un modo de juego moderno temprano:

modelo escalable de reestructuracion:
Code: [Select]
/EngineRoot
    /src
        /Core             <- Sistema base: logs, utilidades, memory, etc.
        /Graphics         <- Renderer, recursos, texturas, shaders, materiales
        /Scene            <- Objetos, entidades, transformaciones, culling
        /Game             <- Lógica específica del juego, reglas, mods, eventos
        /UI               <- Sistema de UI/HUD/menus
        /Input            <- Teclado, mouse, gamepad, bindings
        /Audio            <- (Opcional) Manejo de sonido/música
        /Platform         <- Adaptación a Windows/Linux, paths, archivos, ventanas
        /Tools            <- Herramientas internas (editores, converters, exporters)
    /assets
        /models
        /textures
        /sounds
    /shaders
    /include
    /cmake
    main.cpp
    CMakeLists.txt

ahora planteando la estrategia de menjar algo mas sofisticado

Code: [Select]
#pragma once

class SceneInstance
{
public:
virtual ~SceneInstance() = default;

virtual int GetID() const = 0;

// Inicialización de la escena (carga recursos, setup)
virtual void Init() = 0;

// Liberación de recursos
virtual void Cleanup() = 0;

// Se llama cada frame para actualizar la lógica de la escena
virtual void Update(float deltaTime) = 0;

// Se llama cada frame para renderizar la escena
virtual void Render() = 0;

// Eventos de entrada, si quieres procesarlos aquí
virtual void OnInput(/* ... */) { /* Opcional */ }
};

class SceneManager
{
public:
// Cambia a una nueva escena (descarta la actual)
void ChangeScene(std::unique_ptr<SceneInstance> newScene);

// Pone una nueva escena sobre la actual (stack)
void PushScene(std::unique_ptr<SceneInstance> scene);

// Quita la escena actual y vuelve a la anterior
void PopScene();

// Llama al update/render de la escena activa
void Update(float deltaTime);
void Render();

// Acceso a la escena actual
void SetFlag(int flag);
int GetCurrentflag();
SceneInstance* GetCurrentScene();
static SceneManager* Instance();
private:
std::stack<std::unique_ptr<SceneInstance>> sceneStack;
};

#define gSceneManager (SceneManager::Instance())

Code: [Select]
void SceneManager::ChangeScene(std::unique_ptr<SceneInstance> newScene)
{
// Limpia y elimina la escena actual
if (!sceneStack.empty())
{
sceneStack.top()->Cleanup();
sceneStack.pop();

g_ConsoleDebug->Write(5, "sacando scene");
}
// Inicializa y agrega la nueva escena
newScene->Init();
sceneStack.push(std::move(newScene));
}

void SceneManager::PushScene(std::unique_ptr<SceneInstance> scene)
{
scene->Init();
sceneStack.push(std::move(scene));
}

void SceneManager::PopScene()
{
if (!sceneStack.empty())
{
sceneStack.top()->Cleanup();
sceneStack.pop();
}
}

void SceneManager::Update(float deltaTime)
{
if (!sceneStack.empty())
{
sceneStack.top()->Update(deltaTime);
}
}

void SceneManager::Render()
{
if (!sceneStack.empty())
{
sceneStack.top()->Render();
}
}

void SceneManager::SetFlag(int flag)
{
if (gSceneManager->GetCurrentflag() != flag)
{
switch (flag)
{
case WEBZEN_SCENE:
this->ChangeScene(std::make_unique<SceneLoading>());
break;
//case LOADING_SCENE:
// this->ChangeScene(std::make_unique<SceneLogin>());
// break;
case LOG_IN_SCENE:
this->ChangeScene(std::make_unique<SceneLogin>());
break;
case CHARACTER_SCENE:
this->ChangeScene(std::make_unique<SceneCharacter>());
break;
//case MAIN_SCENE:
// this->ChangeScene(std::make_unique<SceneCharacter>());
// break;
}
}
}

int SceneManager::GetCurrentflag()
{
return sceneStack.empty() ? NON_SCENE : sceneStack.top()->GetID();
}

SceneInstance* SceneManager::GetCurrentScene()
{
return sceneStack.empty() ? nullptr : sceneStack.top().get();
}

SceneManager* SceneManager::Instance()
{
static SceneManager s_Instance;
return &s_Instance;
}

uno de los primeros problemas es la gestion de memoria sincronizada, y parcial, otra cosa que se tiene que reestructurar si o si, es el frustrum que en palabras de programacion para juego se le llama frustrum, eso también llega a causar que el problema de carga para el terreno plano sea costoso, que se puede hacer?


Code: [Select]
void MUCullingFace::Frustum3DPlanes(vec3_t position)
{
float proj[16];
float clip[16];
float modelview[16];

glGetFloatv(GL_PROJECTION_MATRIX, proj);
glGetFloatv(GL_MODELVIEW_MATRIX, modelview);

// Multiplicacion OpenGL: clip = proj * modelview
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
clip[i + j * 4] =
modelview[0 + j * 4] * proj[i + 0] +
modelview[1 + j * 4] * proj[i + 4] +
modelview[2 + j * 4] * proj[i + 8] +
modelview[3 + j * 4] * proj[i + 12];
}
}

// Extract and normalize planes
auto normalize = [](float* p) {
float length = sqrtf(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
if (length > 0.0f) {
p[0] /= length; p[1] /= length; p[2] /= length; p[3] /= length;
}
};

// Left
fFrustumPlane[0][0] = clip[3] + clip[0];
fFrustumPlane[0][1] = clip[7] + clip[4];
fFrustumPlane[0][2] = clip[11] + clip[8];
fFrustumPlane[0][3] = clip[15] + clip[12];
normalize(fFrustumPlane[0]);

// Right
fFrustumPlane[1][0] = clip[3] - clip[0];
fFrustumPlane[1][1] = clip[7] - clip[4];
fFrustumPlane[1][2] = clip[11] - clip[8];
fFrustumPlane[1][3] = clip[15] - clip[12];
normalize(fFrustumPlane[1]);

// Bottom
fFrustumPlane[2][0] = clip[3] + clip[1];
fFrustumPlane[2][1] = clip[7] + clip[5];
fFrustumPlane[2][2] = clip[11] + clip[9];
fFrustumPlane[2][3] = clip[15] + clip[13];
normalize(fFrustumPlane[2]);

// Top
fFrustumPlane[3][0] = clip[3] - clip[1];
fFrustumPlane[3][1] = clip[7] - clip[5];
fFrustumPlane[3][2] = clip[11] - clip[9];
fFrustumPlane[3][3] = clip[15] - clip[13];
normalize(fFrustumPlane[3]);

// Near
fFrustumPlane[4][0] = clip[3] + clip[2];
fFrustumPlane[4][1] = clip[7] + clip[6];
fFrustumPlane[4][2] = clip[11] + clip[10];
fFrustumPlane[4][3] = clip[15] + clip[14];
normalize(fFrustumPlane[4]);

// Far
fFrustumPlane[5][0] = clip[3] - clip[2];
fFrustumPlane[5][1] = clip[7] - clip[6];
fFrustumPlane[5][2] = clip[11] - clip[10];
fFrustumPlane[5][3] = clip[15] - clip[14];

normalize(fFrustumPlane[5]);
}

muchas de las cosas que se tienen que re estructurar no entra la logica del juego, si no la implementacion de como esta planteado el manejo y control de los callback de opengl y las limitaciones que se realizan en la expansion de uso en la camara

Para realmente modernizar, se saca completamente el model view y se usa una proyeccion con camara:

u_projectionMatrix * u_viewMatrix * u_modelMatrix

El juego en si utiliza 2 chequeaos para renderizar el terreno:
1: Escanea el primer 'frustum' (si, entre comillas porque no es el verdadero frustrum) que es cuadrado y formado por CameraFOV, CameraViewNear y CameraViewFar
2: Si esta dentro del primer 'frustrum', escanea el segundo frustrum (este si es el verdadero, es el que renderiza tu pantalla) y si esta dentro entonces renderiza el terreno

Para optimizar el renderizado del terreno, se deberia renderizar en chunks y/o utilizar VAO/VBO/EBO, pero para estas funciones ya nesecitas OpenGL 2.0 como minimo.
Con VAOs puedo renderizar el terreno completo (256 * 256) a 60 fps - estoy porteando la version 97d a OGL 2.0.

It’s called a tetrahedron, and yes, you’re implementing an idea quite similar to the work I’m doing. However, I’m a bit skeptical about your ability to render 256x256 while still maintaining 60 FPS. I’m not entirely sure what you mean, are you only rendering the terrain, or can you render the entire set of objects in the map as well?


Offline Feche #13 Posteado: August 08, 2025, 01:00:56 PM

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Dedicado
  • Posts: 50
  • Gracias recibida: 1509
  • ar
Para realmente modernizar, se saca completamente el model view y se usa una proyeccion con camara:

u_projectionMatrix * u_viewMatrix * u_modelMatrix

El juego en si utiliza 2 chequeaos para renderizar el terreno:
1: Escanea el primer 'frustum' (si, entre comillas porque no es el verdadero frustrum) que es cuadrado y formado por CameraFOV, CameraViewNear y CameraViewFar
2: Si esta dentro del primer 'frustrum', escanea el segundo frustrum (este si es el verdadero, es el que renderiza tu pantalla) y si esta dentro entonces renderiza el terreno

Para optimizar el renderizado del terreno, se deberia renderizar en chunks y/o utilizar VAO/VBO/EBO, pero para estas funciones ya nesecitas OpenGL 2.0 como minimo.
Con VAOs puedo renderizar el terreno completo (256 * 256) a 60 fps - estoy porteando la version 97d a OGL 2.0.

Puedes usar Glew para actualizar Opengl hookeando la función que inicializa el contexto y guardando los valores en las direcciones de memoria originales del main.

Descompile la version 97d, trabajo con source code

Gracias:


Offline Feche #14 Posteado: August 08, 2025, 01:03:15 PM

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Dedicado
  • Posts: 50
  • Gracias recibida: 1509
  • ar
It’s called a tetrahedron, and yes, you’re implementing an idea quite similar to the work I’m doing. However, I’m a bit skeptical about your ability to render 256x256 while still maintaining 60 FPS. I’m not entirely sure what you mean, are you only rendering the terrain, or can you render the entire set of objects in the map as well?

I can render 256 * 256 terrain tiles without objects at 60 FPS (the whole map basically) - I am still working on object rendering, so for now it is just terrain tiles.

Gracias:


Offline emersonx13 #15 Posteado: August 08, 2025, 01:33:17 PM | Modificado: August 08, 2025, 02:02:23 PM by emersonx13

  • MAESTRO

  • US. DE HONOR

  • LEYENDA

  • 3D Maker
  • 0 puntos por ventas
  • *
  • *
  • Rank: Puto amo
  • Posts: 531
  • Gracias recibida: 38029
  • br
Donate for my Work

BTC: 1HnXqN1wAh3EUC2Gi4WVH5Cj8fmihgeQze

Gracias:


Offline samsunggon #16 Posteado: August 08, 2025, 10:40:21 PM

  • 0 puntos por ventas
  • *
  • Rank: Puto amo
  • Posts: 471
  • Gracias recibida: 2466
  • ph
where to get that files?


DISCORD: valentino1515


Offline TranLam.Noria #17 Posteado: August 10, 2025, 09:44:27 AM

  • 0 puntos por ventas
  • *
  • Rank: Principiante
  • Posts: 7
  • Gracias recibida: 25
It’s called a tetrahedron, and yes, you’re implementing an idea quite similar to the work I’m doing. However, I’m a bit skeptical about your ability to render 256x256 while still maintaining 60 FPS. I’m not entirely sure what you mean, are you only rendering the terrain, or can you render the entire set of objects in the map as well?

I can render 256 * 256 terrain tiles without objects at 60 FPS (the whole map basically) - I am still working on object rendering, so for now it is just terrain tiles.


Instead of optimizing for terrain rendering, I think optimizing to increase the view range for both objects and terrain would be more practical. This will be a gift for all players who enjoy hunting, participating in Castle Siege, or simply, from now on, all events taking place in 'super large' maps like Vulcanus will no longer be too challenging.

Gracias:


Offline Feche #18 Posteado: August 12, 2025, 11:00:00 PM

  • C++ Coder
  • 0 puntos por ventas
  • *
  • Rank: Dedicado
  • Posts: 50
  • Gracias recibida: 1509
  • ar
It’s called a tetrahedron, and yes, you’re implementing an idea quite similar to the work I’m doing. However, I’m a bit skeptical about your ability to render 256x256 while still maintaining 60 FPS. I’m not entirely sure what you mean, are you only rendering the terrain, or can you render the entire set of objects in the map as well?

I can render 256 * 256 terrain tiles without objects at 60 FPS (the whole map basically) - I am still working on object rendering, so for now it is just terrain tiles.


Instead of optimizing for terrain rendering, I think optimizing to increase the view range for both objects and terrain would be more practical. This will be a gift for all players who enjoy hunting, participating in Castle Siege, or simply, from now on, all events taking place in 'super large' maps like Vulcanus will no longer be too challenging.

Yeah, that is what I said. I am working on that - here I am rendering Lorencia @ ~45fps, on Stadium I can get 60fps, Noria which is heavier ~20fps, but I still have room for improvements + migrate to OGL 3.0




Gracias:


Offline emersonx13 #19 Posteado: August 22, 2025, 03:23:08 AM | Modificado: August 26, 2025, 10:03:13 PM by emersonx13

  • MAESTRO

  • US. DE HONOR

  • LEYENDA

  • 3D Maker
  • 0 puntos por ventas
  • *
  • *
  • Rank: Puto amo
  • Posts: 531
  • Gracias recibida: 38029
  • br
Donate for my Work

BTC: 1HnXqN1wAh3EUC2Gi4WVH5Cj8fmihgeQze

Gracias:


Solo usuarios registrados pueden comentar y agradecer, Logueate o Registrate


 

Related Topics

  Subject / Started by Replies Last post
0 Replies
842 Views
Last post May 27, 2018, 03:07:01 PM
by 🐼 𝙋 𝘼 𝙉 𝘿 𝘼 🐼
0 Replies
819 Views
Last post June 04, 2018, 06:12:38 PM
by 🐼 𝙋 𝘼 𝙉 𝘿 𝘼 🐼
1 Replies
1933 Views
Last post February 20, 2020, 03:37:21 PM
by TryMenow
42 Replies
2162 Views
Last post April 30, 2025, 10:01:50 AM
by MuRevolution
0 Replies
292 Views
Last post April 23, 2025, 06:13:21 AM
by TranLam.Noria