ShotGuns Max-Clip [ORPHEU]
#1

PREFACIO

Hace tiempo cree un tema donde discutí acerca de una cuestión referente al clip de las escopetas (específicamente la XM1014).

Básicamente el problema era debido a una condicional al inicio de la función relacionada al Reload() del arma; finalmente gracias a mucha ayuda de plugins/addons de terceros, logre realizar una modificación que me permitiera cambiar una secuencia de bytes para así reemplazar el valor del condicional antes mencionado, y logre realizarlo, por lo tanto quería compartirlo con ustedes.



Este plugin permite cambiar la cantidad máxima de balas que puede tener una escopeta (cualquiera de los dos tipos por defecto del CS 1.6); lo que hace es buscar la dirección de cuatro condicionales que se hallan en cuatro funciones del MOD (GameDLL o como le quieran decir), dos de ellas que son las funciones especificas de recarga de cada arma, y las otras dos que son funciones auxiliares donde se ve involucrado la llamada a las funciones de recarga, de cumplirse ciertos requisitos. Después de encontrar tales direcciones, procede a parchear la memoria (los bytes de las instrucciones, cambiando un par de ellos por la cantidad de balas máxima de cada arma).

El plugin posee dos comandos para poder cambiar el max-clip de cada arma ("change_xm1014_maxclip" y "change_m3_maxclip", por conveniencia). Así como también incluye distintas directivas de preprocesador (defines, en este caso), que permiten:
  • 1) Parchear la memoria automáticamente al iniciar el mapa (si se cumple una condición, explicada más abajo).

    2) Guardar un registro, mediante LOGs, de todas las veces que fue parcheada la memoria.

    3) Especificar un método de chequeo, que permite parchear la memoria al iniciar el mapa y que puede ser realizado de tres maneras (explicadas mejor en el archivo fuente SMA):
    • 3.1) No chequea nada, es decir que el parcheo de memoria tiene lugar en cada inicio del mapa.

      3.2) En este caso, se comparara información guardada locamente en el servidor (una cadena), con (otra) una cadena que se encuentra definida en el archivo SMA.

      3.3) Es igual al anterior, pero lo que se compara es un resultado guardado, que es igual a la suma de valores por defecto para el max-clip de cada arma (constantes pueden hallarse en el código, junto con explicación mas detallada).
También hay varias partes del código destinadas a explicar el funcionamiento de ciertas cosas; trate de ser lo más explicativo y sencillo posible aunque reconozco que quizá tenga algunas fallas teóricas. Al final del código, deje un comentario donde explicada el porqué de realizar un chequeo previo al iniciar el mapa para parchear memoria, que quizá no sea del todo cierto, pero que mientras estuve testeando no vi ningún inconveniente en llevarlo a cabo.

Existe un pequeño bug, del cual no he podido encontrar solución, y que se trata de que al parchear el max-clip con una cantidad de 128+, el juego pareciera no llegar a tal limite, y sigue recargando balas, en cuanto tenga el jugador balas en sus manos (si remueven el limite en el código, y prueban ustedes mismos, verán a que me refiero). He intentado diferentes formas de 'fixearlo', pero todas crasheaban el servidor. En tanto encuentre una solución, la posteare.

Como nota final, el plugin fue probado bajo el SO Windows, usando el binario mas actualizado que tenia (del STEAM), por lo que supongo que no debería haber problemas si se usa en otras PCs con el mismo sistema y binario. Ahora el tema de Linux no he podido comprobarlo ya que no tenia con quien testear y tampoco tenia el SO, pero técnicamente debería funcionar. Cualquier inconveniente que se tenga en cuanto al plugin, no duden en hacerlo saber en este mismo tema.

Por último, doy créditos a los usuarios @meTaLiCroSS y @Arkshine, el primero por una pequeña ayuda (mas que nada una foto de la secuencia de bytes originales en Linux), y el segundo por varios plugins realizados, que me permitieron realizar lo que buscaba.

Código:
Eso es todo, espero que les guste el plugin.

CÓDIGO
Código PHP:
#include AMXMODX.INC
#include ORPHEU_MEMORY.INC

// Especifica si debe parchearse la memoria en cada inicio del servidor (encendido, cambio de mapa, restart, etc).
#define M_PatchMemoryAtServerStart

// Especifica si se desea llevar un registro, utilizando LOGs, respecto a todas las veces que ha sido
// parcheada la memoria (con las caracteristicas de cada caso).
#define M_WriteMemoryPatchLOGs

/*
Especifica el metodo de chequeo, si se tiene activado el parcheo automatico al iniciar el mapa, que debera
realizarse justo antes de llevar a cabo dicho parche en memoria (razón de esto al final).

Los valores para usar son:

(*) DONT_CHECK_NOTHING (no chequear nada): Especifica que ningun chequeo se llevara a cabo.

(*) CHECK_BY_STRING (chequear mediante cadena): Especifica que debera compararse la información guardada localmente
en el servidor (al llamarse a plugin_end()), con una cadena de texto especificada más abajo, y de esa manera determinar 
si debe o no parchearse la memoria.

(*) CHECK_BY_DEFAULT_VALUE (chequear mediante valores por defecto): Similar al anterior, pero en lugar de chequear una cadena,
compara el resultado de la suma de max-clip por defecto para ambas escopetas (constantes "CI_DefaultNewClipToXM1014" y "CI_DefaulNewClipToM3"),
con otro valor guardado localmente, y si es el mismo que el anterior no se llevara a cabo el parche.
*/

#define M_CheckMemoryPatchAtServerStart        CHECK_BY_STRING

enum _:E_MemoryPatchChecksTypes
{
    
DONT_CHECK_NOTHING,
    
CHECK_BY_STRING,
    
CHECK_BY_DEFAULT_VALUE
}

const 
CI_AccessToChangeClip ADMIN_BAN

// Maxima cantidad de clip que puede asignarse a las escopetas, usando este plugin,
// a causa de un pequeño 'bug' al llegar a 128+

const CI_MaxClipValues 127

#if defined M_PatchMemoryAtServerStart
    
const CI_DefaultNewMaxClipToXM1014 20 // Maximo clip nuevo por defecto para la XM1014 (si se tiene activado el parcheo automatico).
    
const CI_DefaulNewMaxClipToM3 13 // Maximo clip por defecto para la M3 (si se tiene activado el parcheo automatico).
#endif

#if defined M_WriteMemoryPatchLOGs
    
new const CSZ_MemoryPatchsLogFile[] = "MemoryPatchForShotGuns.LOG" // Archivo donde se llevara el registro de parcheos, si se define su uso.
    
new const CSZ_LogFilesTag[] = "[ORPHEU]"
#endif

#if defined M_CheckMemoryPatchAtServerStart
    #if defined M_PatchMemoryAtServerStart && M_CheckMemoryPatchAtServerStart > DONT_CHECK_NOTHING
        // Llave (key) usada para guardar cierta información localmente en el servidor acerca de cada parche en memoria que se realice,
        // y que sera usada si se tiene activado el chequeo del parcheo.
        
new const CSZ_MemoryPatchLocalInfo[] = "IsMemoryPatchForShotGuns"
    
        
#if M_CheckMemoryPatchAtServerStart == CHECK_BY_STRING
            // Si el chequeo es por cadena, esta cadena sera la usada para comparar.
            
new const CSZ_StringToCheckMemoryPatch[] = "true"
        
#endif
    #endif
#endif

new const CSZ_PluginTag[] = "[SHOTGUNS CLIP]"

new const CSZ_XM1014MemoryReloadClip[] = "XM_RC_Reload"
new const CSZ_XM1014MemoryWeaponIdleClip[] = "XM_RC_WeaponIdle"

new const CSZ_M3MemoryReloadClip[] = "M3_RC_Reload"
new const CSZ_M3MemoryWeaponIdleClip[] = "M3_RC_WeaponIdle"

new const CSZ_ByteMemory[] = "byte"

new bool:BO_IsLinuxSeverSZ_NewClip[4], A_BytesToReplace[3];

public 
plugin_init() 
{    
     
// Determinar si el servidor esta operando bajo el SO Linux (ya que los bytes a reemplazar difieren en el binario de Windows).
    
BO_IsLinuxSever bool:is_linux_server()
    
    
// Si se llevara a cabo un parcheo en cada inicio del mapa.
    #if defined M_PatchMemoryAtServerStart
    
{
        
// Si se llevara a cabo un chequeo anterior al parche.
        #if defined M_CheckMemoryPatchAtServerStart
        
{
            
// Si el metodo de chequeo a realizar es por cadena.
            #if M_CheckMemoryPatchAtServerStart == CHECK_BY_STRING
            
{
                new 
SZ_LocalInfo[6];
            
                
get_localinfo(CSZ_MemoryPatchLocalInfoSZ_LocalInfocharsmax(SZ_LocalInfo))
                
                
// SZ_LocalInfo contiene información guardada localmente en el servidor (usando la llave almacenada en CSZ_MemoryPatchLocalInfo).
                // Mientras que 'CSZ_StringToCheckMemoryPatch' es quien contiene la cadena a comparar (por defecto "true").
                
                
if (equal(SZ_LocalInfoCSZ_StringToCheckMemoryPatch))
                    goto 
RegisterCommands// Aquí nos salteamos el parcheo en memoria, basandose en que ya fue realizado.
            
}
            
#else
            
{
                
// Caso contrario, si es mediante valores por defecto.
                #if M_CheckMemoryPatchAtServerStart == CHECK_BY_DEFAULT_VALUE
                
{
                    
get_localinfo(CSZ_MemoryPatchLocalInfoSZ_NewClipcharsmax(SZ_NewClip))
                    
                    
// Como veran, se compara el valor almacenado en "SZ_NewClip" (usada para evitar el uso de otra variable),
                    // con la suma de los valores por defecto para el max-clip de las escopetas.
                    
                    
if (str_to_num(SZ_NewClip) == (CI_DefaultNewClipToXM1014 CI_DefaulNewClipToM3))
                        goto 
RegisterCommands// Aquí nos salteamos el parcheo en memoria, basandose en que ya fue realizado.
                
}
                
#endif
            
}
            
#endif
        
}
        
#endif
        
        // Si el servidor utiliza el binario de Linux, reemplazamos los bytes en el mismo.
        
if (BO_IsLinuxSever)
        {
            
/*
            En Linux, las intrucciones originales son estas (según mi binario):
            
            CXM1014::Reload()
                83 F9 07    ->    cmp     ecx, 7 (byte 0x7 o también 0x07)
            
            CXM1014::WeaponIdle()
                83 F8 07    ->    cmp     eax,  7 (byte 0x7 o también 0x07)
                
            CM3::Reload()
                83 F9 08    ->    cmp     ecx, 8 (byte 0x8 o también 0x08)
                
            CM3::WeaponIdle()
                83 F8 08    ->    cmp     eax, 8 (byte 0x8 o también 0x08)
                
            Y como pueden ver, es el ultimo byte el que es sobre-escrito por el nuevo valor por defecto para cada escopeta.
            */
            
            // Parcheamos la memoria.
            
            
UTIL_PatchMemory(CSZ_XM1014MemoryReloadClip, { 0x830xF9CI_DefaultNewMaxClipToXM1014 }) // CXM1014::Reload()
            
UTIL_PatchMemory(CSZ_XM1014MemoryWeaponIdleClip, { 0x830xF8CI_DefaultNewMaxClipToXM1014 }) // CXM1014::WeaponIdle()
            
            // Parcheamos la memoria.
            
            
UTIL_PatchMemory(CSZ_M3MemoryReloadClip, { 0x830xF9CI_DefaulNewMaxClipToM3 }) // CM3::Reload()
            
UTIL_PatchMemory(CSZ_M3MemoryWeaponIdleClip, { 0x830xF8CI_DefaulNewMaxClipToM3 }) // CM3::WeaponIdle()
        
}
        
// Caso contrario, reemplazamos los bytes que aparecen en el binario de Windows.
        
else
        {
            
/*
            En Windows, las intrucciones originales son estas (según mi binario):
            
            sub_10010640 (CXM1014::Reload())
                83 FF 07    ->    cmp     edi, 7 (byte 0x7 o también 0x07)
            
            sub_100107F0 (CXM1014::WeaponIdle())
                83 F8 07    ->    cmp     eax, 7 (byte 0x7 o también 0x07)
                
            sub_1000A4A0 (CM3::Reload())
                83 FF 08    ->    cmp     edi, 8 (byte 0x8 o también 0x08)
                
            sub_1000A5D0 (CM3::WeaponIdle())
                83 F8 08    ->    cmp     eax, 8 (byte 0x8 o también 0x08)
                
            Y como pueden ver, es el ultimo byte el que es sobre-escrito por el nuevo valor por defecto para cada escopeta.
            */
            
            // Parcheamos la memoria.
            
            
UTIL_PatchMemory(CSZ_XM1014MemoryReloadClip, { 0x830xFFCI_DefaultNewMaxClipToXM1014 }) // sub_10010640 (CXM1014::Reload())
            
UTIL_PatchMemory(CSZ_XM1014MemoryWeaponIdleClip, { 0x830xF8CI_DefaultNewMaxClipToXM1014 }) // sub_100107F0 (CXM1014::WeaponIdle())
            
            // Parcheamos la memoria.
            
            
UTIL_PatchMemory(CSZ_M3MemoryReloadClip, { 0x830xFFCI_DefaulNewMaxClipToM3 }) // sub_1000A4A0 (CM3::Reload())
            
UTIL_PatchMemory(CSZ_M3MemoryWeaponIdleClip, { 0x830xF8CI_DefaulNewMaxClipToM3 }) // sub_1000A5D0 (CM3::WeaponIdle())
        
}
    }
    
#endif
    
    
register_plugin("ShotGuns Max-Clip""With Orpheu""By Chamo.")
    
    
/*
    Si se llevara a cabo tanto, un parcheo en cada inicio del mapa como un chequeo anterior al parche,
    y el metodo a realizar es distinto (mayor que) de 'no hacer nada'.
    
    Basicamente hago esto por el tema del GOTO, ya que de no hacerlo, no encontraria referencias a 'RegisterCommands' para "saltar",
    desde donde es usada la intrucción hasta donde se encuentre la referencia (se que la explicación esta para el culo jaja,
    pero no conozco casi nada el funcionamiento de esta instrucción).
    */
    #if defined M_PatchMemoryAtServerStart && defined M_CheckMemoryPatchAtServerStart && M_CheckMemoryPatchAtServerStart > DONT_CHECK_NOTHING
    
{
        
RegisterCommands:
        {
            
// Registramos los comandos para cambiar el clip de las escopetas.
                
            
register_clcmd("change_xm1014_maxclip""CLCOMMAND_ChangeXM1014MaxClip")
            
register_clcmd("change_m3_maxclip""CLCOMMAND_ChangeM3MaxClip")
        }
    }
    
#else
    
{
        
// Registramos los comandos para cambiar el clip de las escopetas.
        
        
register_clcmd("change_xm1014_maxclip""CLCOMMAND_ChangeXM1014MaxClip")
        
register_clcmd("change_m3_maxclip""CLCOMMAND_ChangeM3MaxClip")
    }
    
#endif
}

public 
plugin_end()
{
    
// Si se llevara a cabo tanto, un parcheo en cada inicio del mapa, como un chequeo antes de dicho parche.
    #if defined M_PatchMemoryAtServerStart && defined M_CheckMemoryPatchAtServerStart
    
{
        
// Si el metodo de chequeo a realizar es por cadena.
        #if M_CheckMemoryPatchAtServerStart == CHECK_BY_STRING
            // Guardamos en la información local del servidor, la cadena que sera comparada en cada inicio del plugin.
            
set_localinfo(CSZ_MemoryPatchLocalInfoCSZ_StringToCheckMemoryPatch)
        
#else
        
{
            
// Caso contrario, si es mediante valores por defecto.
            #if M_CheckMemoryPatchAtServerStart == CHECK_BY_DEFAULT_VALUE
            
{
                new 
SZ_LocalInfo[sizeof SZ_NewClip];
            
                
formatex(SZ_LocalInfocharsmax(SZ_LocalInfo), "%d", (CI_DefaultNewClipToXM1014 CI_DefaulNewClipToM3))
                
                
// Guardamos el resultado de la suma de valores por defecto, que sera comparado en cada inicio del plugin.
                
set_localinfo(CSZ_MemoryPatchLocalInfoSZ_LocalInfo)
            }
            
#endif
        
}
        
#endif
    
}
    
#endif
}

public 
CLCOMMAND_ChangeXM1014MaxClip(const I_Client)
{
    if (!(
get_user_flags(I_Client) & CI_AccessToChangeClip))
    {
        
client_print(I_Clientprint_chat"%s No tienes acceso para usar este comando!."CSZ_PluginTag)
        
        return 
PLUGIN_HANDLED_MAIN;
    }
    
    
read_argv(1SZ_NewClipcharsmax(SZ_NewClip))
    
    
SZ_NewClip[0] = str_to_num(SZ_NewClip)
    
    
// Si no es un valor valido (para evitar bugs).
    
if (!SZ_NewClip[0] || SZ_NewClip[0] > CI_MaxClipValues)
    {
        
client_print(I_Clientprint_chat"%s El número escrito, no es valido!."CSZ_PluginTag)
        
        return 
PLUGIN_HANDLED_MAIN;
    }
    
    
// Detectamos si el servidor usa el binario de Linux, en cuyo caso reemplazamos los bytes respectivos.
    
if (BO_IsLinuxSever)
    {
        
A_BytesToReplace[0] = 0x83 // Byte original (Linux) -> CXM1014::Reload()
        
A_BytesToReplace[1] = 0xF9 // Byte original (Linux) ->  CXM1014::Reload()
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_XM1014MemoryReloadClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_XM1014MemoryReloadClipA_BytesToReplace)
        
        
A_BytesToReplace[0] = 0x83 // Byte original (Linux) -> CXM1014::WeaponIdle()
        
A_BytesToReplace[1] = 0xF8 // Byte original (Linux) -> CXM1014::WeaponIdle()
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_XM1014MemoryWeaponIdleClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_XM1014MemoryWeaponIdleClipA_BytesToReplace)
    }
    
// Caso contrario, el servidor usa el binario de Windows, en cuyo caso reemplazamos los bytes respectivos.
    
else
    {
        
A_BytesToReplace[0] = 0x83 // Byte original (Windows) -> sub_10010640 (CXM1014::Reload())
        
A_BytesToReplace[1] = 0xFF // Byte original (Windows) -> sub_10010640 (CXM1014::Reload())
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG, información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_XM1014MemoryReloadClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_XM1014MemoryReloadClipA_BytesToReplace)
        
        
A_BytesToReplace[0] = 0x83 // Byte original (Windows) -> sub_100107F0 (CXM1014::WeaponIdle())
        
A_BytesToReplace[1] = 0xF8 // Byte original (Windows) -> sub_100107F0 (CXM1014::WeaponIdle())
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_XM1014MemoryWeaponIdleClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_XM1014MemoryWeaponIdleClipA_BytesToReplace)
    }
    
    return 
PLUGIN_HANDLED_MAIN;
}

public 
CLCOMMAND_ChangeM3MaxClip(const I_Client)
{
    if (!(
get_user_flags(I_Client) & CI_AccessToChangeClip))
    {
        
client_print(I_Clientprint_chat"%s No tienes acceso para usar este comando!."CSZ_PluginTag)
        
        return 
PLUGIN_HANDLED_MAIN;
    }
    
    
read_argv(1SZ_NewClipcharsmax(SZ_NewClip))
    
    
SZ_NewClip[0] = str_to_num(SZ_NewClip)
    
    
// Si no es un valor valido (para evitar bugs).
    
if (!SZ_NewClip[0] || SZ_NewClip[0] > CI_MaxClipValues)
    {
        
client_print(I_Clientprint_chat"%s El número escrito, no es valido!."CSZ_PluginTag)
        
        return 
PLUGIN_HANDLED_MAIN;
    }
    
    
// Detectamos si el servidor usa el binario de Linux, en cuyo caso reemplazamos los bytes respectivos.
    
if (BO_IsLinuxSever)
    {
        
A_BytesToReplace[0] = 0x83 // Byte original (Linux) -> CM3::Reload()
        
A_BytesToReplace[1] = 0xF9 // Byte original (Linux) -> CM3::Reload()
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG, información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_M3MemoryReloadClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_M3MemoryReloadClipA_BytesToReplace)
        
        
A_BytesToReplace[0] = 0x83 // Byte original (Linux) -> CM3::WeaponIdle()
        
A_BytesToReplace[1] = 0xF8 // Byte original (Linux) -> CM3::WeaponIdle()
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG, información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_M3MemoryWeaponIdleClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_M3MemoryWeaponIdleClipA_BytesToReplace)
    }
    
// Caso contrario, el servidor usa el binario de Windows, en cuyo caso reemplazamos los bytes respectivos.
    
else
    {
        
A_BytesToReplace[0] = 0x83 // Byte original (Windows) -> sub_1000A4A0 (CM3::Reload())
        
A_BytesToReplace[1] = 0xFF // Byte original (Windows) -> sub_1000A4A0 (CM3::Reload())
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
            
        // Si se registrara en un LOG, información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_M3MemoryReloadClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_M3MemoryReloadClipA_BytesToReplace)
        
        
A_BytesToReplace[0] = 0x83 // Byte original (Windows) -> sub_1000A5D0 (CM3::WeaponIdle())
        
A_BytesToReplace[1] = 0xF8 // Byte original (Windows) -> sub_1000A5D0 (CM3::WeaponIdle())
        
A_BytesToReplace[2] = SZ_NewClip[0// Valor nuevo que sobre-escribira el anterior.
        
        // Si se registrara en un LOG, información relacionada a este parche en la memoria.
        #if defined M_WriteMemoryPatchLOGs
            
log_to_file(CSZ_MemoryPatchsLogFile"%s - Iniciando parche en la memoria para: %s (valor asignado: %d)"CSZ_LogFilesTagCSZ_M3MemoryWeaponIdleClipA_BytesToReplace[(sizeof A_BytesToReplace 1)])
        
#endif
        
        // Parcheamos la memoria.
        
        
UTIL_PatchMemory(CSZ_M3MemoryWeaponIdleClipA_BytesToReplace)
    }
    
    return 
PLUGIN_HANDLED_MAIN;
}

// UTILIDAD (gracias a Arkshine), para parchear memoria (en el caso de este plugin, reemplazar una firma/cadena de bytes).
UTIL_PatchMemory(const SZ_MemoryDataName[], const A_BytesToReplace[], const I_BytesLen sizeof A_BytesToReplace)
{
    new 
I_Address;
    
    
OrpheuMemoryGet(SZ_MemoryDataNameI_Address)
    
    for (new 
II_BytesLenI++)
    {
        
OrpheuMemorySetAtAddress(I_AddressCSZ_ByteMemory1A_BytesToReplace[I], I_Address)
        
        
I_Address++
    }
    
    
// Si se registrara en un LOG, información relacionada a este parche en la memoria.
    #if defined M_WriteMemoryPatchLOGs
    
{
        
log_to_file(CSZ_MemoryPatchsLogFile"%s - Parche en la memoria realizado con exito!."CSZ_LogFilesTag)
        
log_to_file(CSZ_MemoryPatchsLogFile"%s - Memoria parcheada: %s (valor asignado: %d)"CSZ_LogFilesTagSZ_MemoryDataNameA_BytesToReplace[(I_BytesLen 1)])
    }
    
#endif
}

/*
EXPLICACIÓN DEL CHEQUEO PARA INTENTAR PARCHEAR MEMORIA:

La razón es sencilla; cuando nosotros parcheamos la memoria por primera ves, esta quedara guardada
tal cual esta, y de esa manera, cada vez que se reinicie/cambie el mapa, el max-clip de las escopetas
se mantendrá constante. Afirmaría que esto es debido a que la librería en cuestión (mp.dll para Windows/
cs.so para Linux), es cargada una sola ves al inicializar el HLDS, por ende como bien dije anteriormente,
no habría razón´ aparente para volver a cargar esta librería, de esa manera la información se mantendría "constante".

Ahora, no sé si las natives OrpheuMemoryReplace(AtAddress) funcionen de la misma manera que OrpheuMemorySetAtAddress,
y de ser asi, el resultado deberia ser el mismo.

Y la justificación para usar dos métodos de chequeo, es por que, quizá algunos utilicen este plugin tal
cual esta, y quizá cambien el max-clip ocasionalmente, entonces suponiendo que el servidor se mantenga
en pie todo este tiempo, solamente se parchearia automáticamente la memoria, la primera vez que el plugin
se cargo. Ya las demás veces no habría razón para parchear la memoria, dado que la información debería
ser la misma. 

Una acotación, es que en el "chequeo mediante valores por defecto", puede surgir el caso de que la memoria
se parchee más de una vez, por ejemplo, si el plugin define valores por defecto como 15 y 32 (para la
XM1014 y la M3 respectivamente), si de casualidad queremos cambiar ese valor directamente en el plugin
y compilarlo, para después reiniciar el mapa y probar, obviamente si se parcheara la memoria, dado
que el valor guardado anteriormente en el servidor (la suma de 15 y 32 = 47), sera diferente
de la suma de valores por defecto que acabamos de modificar recién en el plugin.

Eso es todo, espero que les guste el plugin.
*/ 

ARCHIVO MEMORY (debe ser guardado en orpheu/memory, como un archivo sin extensión):
Código:
[
    {
        "name"            :        "XM_RC_Reload",
        "library"        :        "mod",
        "type"            :        "int",
        "memoryType"    :        "code",
        "identifiers"    :        
        [
            {
                "os"    :    "windows",
                "mod"    :    "cstrike",
                "value"    :    0x1066C
            },
            {
                "os"    :    "linux",
                "mod"    :    "cstrike",
                "value"    :    0x5EAEF
            }
        ]
    },
    {
        "name"            :        "XM_RC_WeaponIdle",
        "library"        :        "mod",
        "type"            :        "int",
        "memoryType"    :        "code",
        "identifiers"    :        
        [
            {
                "os"    :    "windows",
                "mod"    :    "cstrike",
                "value"    :    0x108A3
            },
            {
                "os"    :    "linux",
                "mod"    :    "cstrike",
                "value"    :    0x5E9CC
            }
        ]
    },
    {
        "name"            :        "M3_RC_Reload",
        "library"        :        "mod",
        "type"            :        "int",
        "memoryType"    :        "code",
        "identifiers"    :        
        [
            {
                "os"    :    "windows",
                "mod"    :    "cstrike",
                "value"    :    0x0A4CC
            },
            {
                "os"    :    "linux",
                "mod"    :    "cstrike",
                "value"    :    0x5181F
            }
        ]
    },
    {
        "name"            :        "M3_RC_WeaponIdle",
        "library"        :        "mod",
        "type"            :        "int",
        "memoryType"    :        "code",
        "identifiers"    :        
        [
            {
                "os"    :    "windows",
                "mod"    :    "cstrike",
                "value"    :    0x0A683
            },
            {
                "os"    :    "linux",
                "mod"    :    "cstrike",
                "value"    :    0x516FC
            }
        ]
    }
]
Responder


Salto de foro:


Usuarios navegando en este tema: 1 invitado(s)