mirror of
https://github.com/accelerator74/l4dtoolz.git
synced 2024-12-22 14:37:26 +08:00
v2.0.0
This commit is contained in:
parent
7f61a5b296
commit
a5ebdd6e82
@ -4,7 +4,7 @@ projectName = 'l4dtoolz'
|
|||||||
# smsdk_ext.cpp will be automatically added later
|
# smsdk_ext.cpp will be automatically added later
|
||||||
sourceFiles = [
|
sourceFiles = [
|
||||||
'l4dtoolz_mm.cpp',
|
'l4dtoolz_mm.cpp',
|
||||||
'signature.cpp',
|
'memutils.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
###############
|
###############
|
||||||
|
83
Makefile
83
Makefile
@ -1,83 +0,0 @@
|
|||||||
# Makefile
|
|
||||||
|
|
||||||
HX_SDK = ../hl2sdk-l4d2
|
|
||||||
HX_METAMOD = ../mmsource
|
|
||||||
#
|
|
||||||
# l4dtoolz_mm.so
|
|
||||||
#
|
|
||||||
HX_INCLUDE = -I. \
|
|
||||||
-I$(HX_METAMOD)/core \
|
|
||||||
-I$(HX_METAMOD)/core/sourcehook \
|
|
||||||
-I$(HX_SDK)/public \
|
|
||||||
-I$(HX_SDK)/public/tier0 \
|
|
||||||
-I$(HX_SDK)/public/tier1 \
|
|
||||||
-I$(HX_SDK)/public/engine \
|
|
||||||
-I$(HX_SDK)/public/mathlib
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_FLAGS = -DSOURCE_ENGINE=9
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_FLAGS += -DSE_EPISODEONE=1 \
|
|
||||||
-DSE_DARKMESSIAH=2 \
|
|
||||||
-DSE_ORANGEBOX=3 \
|
|
||||||
-DSE_BLOODYGOODTIME=4 \
|
|
||||||
-DSE_EYE=5 \
|
|
||||||
-DSE_CSS=6 \
|
|
||||||
-DSE_ORANGEBOXVALVE=7 \
|
|
||||||
-DSE_LEFT4DEAD=8 \
|
|
||||||
-DSE_LEFT4DEAD2=9 \
|
|
||||||
-DSE_ALIENSWARM=10 \
|
|
||||||
-DSE_PORTAL2=11 \
|
|
||||||
-DSE_CSGO=12
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_FLAGS += -DPOSIX \
|
|
||||||
-Dstricmp=strcasecmp \
|
|
||||||
-D_stricmp=strcasecmp \
|
|
||||||
-D_strnicmp=strncasecmp \
|
|
||||||
-Dstrnicmp=strncasecmp \
|
|
||||||
-D_snprintf=snprintf \
|
|
||||||
-D_vsnprintf=vsnprintf \
|
|
||||||
-D_alloca=alloca \
|
|
||||||
-Dstrcmpi=strcasecmp \
|
|
||||||
-Wall \
|
|
||||||
-Werror \
|
|
||||||
-Wno-switch \
|
|
||||||
-Wno-unused \
|
|
||||||
-msse \
|
|
||||||
-DHAVE_STDINT_H \
|
|
||||||
-m32 \
|
|
||||||
-DNDEBUG \
|
|
||||||
-O3 \
|
|
||||||
-funroll-loops \
|
|
||||||
-pipe \
|
|
||||||
-fno-strict-aliasing \
|
|
||||||
-D_LINUX \
|
|
||||||
-mfpmath=sse \
|
|
||||||
-fvisibility=hidden \
|
|
||||||
-Wno-non-virtual-dtor \
|
|
||||||
-Wno-overloaded-virtual \
|
|
||||||
-Wno-deprecated-register \
|
|
||||||
-fno-exceptions \
|
|
||||||
-fno-rtti \
|
|
||||||
-fvisibility-inlines-hidden
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_LIB = Release/l4dtoolz_mm.o \
|
|
||||||
Release/signature.o \
|
|
||||||
$(HX_SDK)/lib/linux/tier1_i486.a \
|
|
||||||
libvstdlib_srv.so \
|
|
||||||
libtier0_srv.so
|
|
||||||
|
|
||||||
#
|
|
||||||
all:
|
|
||||||
mkdir -p Release
|
|
||||||
ln -sf $(HX_SDK)/lib/linux/libvstdlib_srv.so libvstdlib_srv.so;
|
|
||||||
ln -sf $(HX_SDK)/lib/linux/libtier0_srv.so libtier0_srv.so;
|
|
||||||
#
|
|
||||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/l4dtoolz_mm.o -c l4dtoolz_mm.cpp
|
|
||||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/signature.o -c signature.cpp
|
|
||||||
clang $(HX_INCLUDE) $(HX_LIB) -m32 -shared -static-libgcc -ldl -lm -o Release/l4dtoolz_mm.so
|
|
||||||
#
|
|
||||||
rm -rf Release/*.o
|
|
83
Makefile_l4d
83
Makefile_l4d
@ -1,83 +0,0 @@
|
|||||||
# Makefile
|
|
||||||
|
|
||||||
HX_SDK = ../hl2sdk-l4d
|
|
||||||
HX_METAMOD = ../mmsource
|
|
||||||
#
|
|
||||||
# l4dtoolz_mm.so
|
|
||||||
#
|
|
||||||
HX_INCLUDE = -I. \
|
|
||||||
-I$(HX_METAMOD)/core \
|
|
||||||
-I$(HX_METAMOD)/core/sourcehook \
|
|
||||||
-I$(HX_SDK)/public \
|
|
||||||
-I$(HX_SDK)/public/tier0 \
|
|
||||||
-I$(HX_SDK)/public/tier1 \
|
|
||||||
-I$(HX_SDK)/public/engine \
|
|
||||||
-I$(HX_SDK)/public/mathlib
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_FLAGS = -DSOURCE_ENGINE=8
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_FLAGS += -DSE_EPISODEONE=1 \
|
|
||||||
-DSE_DARKMESSIAH=2 \
|
|
||||||
-DSE_ORANGEBOX=3 \
|
|
||||||
-DSE_BLOODYGOODTIME=4 \
|
|
||||||
-DSE_EYE=5 \
|
|
||||||
-DSE_CSS=6 \
|
|
||||||
-DSE_ORANGEBOXVALVE=7 \
|
|
||||||
-DSE_LEFT4DEAD=8 \
|
|
||||||
-DSE_LEFT4DEAD2=9 \
|
|
||||||
-DSE_ALIENSWARM=10 \
|
|
||||||
-DSE_PORTAL2=11 \
|
|
||||||
-DSE_CSGO=12
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_FLAGS += -DPOSIX \
|
|
||||||
-Dstricmp=strcasecmp \
|
|
||||||
-D_stricmp=strcasecmp \
|
|
||||||
-D_strnicmp=strncasecmp \
|
|
||||||
-Dstrnicmp=strncasecmp \
|
|
||||||
-D_snprintf=snprintf \
|
|
||||||
-D_vsnprintf=vsnprintf \
|
|
||||||
-D_alloca=alloca \
|
|
||||||
-Dstrcmpi=strcasecmp \
|
|
||||||
-Wall \
|
|
||||||
-Werror \
|
|
||||||
-Wno-switch \
|
|
||||||
-Wno-unused \
|
|
||||||
-msse \
|
|
||||||
-DHAVE_STDINT_H \
|
|
||||||
-m32 \
|
|
||||||
-DNDEBUG \
|
|
||||||
-O3 \
|
|
||||||
-funroll-loops \
|
|
||||||
-pipe \
|
|
||||||
-fno-strict-aliasing \
|
|
||||||
-D_LINUX \
|
|
||||||
-mfpmath=sse \
|
|
||||||
-fvisibility=hidden \
|
|
||||||
-Wno-non-virtual-dtor \
|
|
||||||
-Wno-overloaded-virtual \
|
|
||||||
-Wno-deprecated-register \
|
|
||||||
-fno-exceptions \
|
|
||||||
-fno-rtti \
|
|
||||||
-fvisibility-inlines-hidden
|
|
||||||
|
|
||||||
#
|
|
||||||
HX_LIB = Release/l4dtoolz_mm.o \
|
|
||||||
Release/signature.o \
|
|
||||||
$(HX_SDK)/lib/linux/tier1_i486.a \
|
|
||||||
libvstdlib.so \
|
|
||||||
libtier0.so
|
|
||||||
|
|
||||||
#
|
|
||||||
all:
|
|
||||||
mkdir -p Release
|
|
||||||
ln -sf $(HX_SDK)/lib/linux/libvstdlib.so libvstdlib.so;
|
|
||||||
ln -sf $(HX_SDK)/lib/linux/libtier0.so libtier0.so;
|
|
||||||
#
|
|
||||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/l4dtoolz_mm.o -c l4dtoolz_mm.cpp
|
|
||||||
clang $(HX_INCLUDE) $(HX_FLAGS) -o Release/signature.o -c signature.cpp
|
|
||||||
clang $(HX_INCLUDE) $(HX_LIB) -m32 -shared -static-libgcc -ldl -lm -o Release/l4dtoolz_mm.so
|
|
||||||
#
|
|
||||||
rm -rf Release/*.o
|
|
20
game_offsets.h
Normal file
20
game_offsets.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#ifndef _INCLUDE_GAME_OFFSETS_
|
||||||
|
#define _INCLUDE_GAME_OFFSETS_
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
int maxplayers_offs = 138; // m_nMaxClientsLimit (in CGameServer::SetMaxClients)
|
||||||
|
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||||
|
#include "l4d1_offsets_win32.h"
|
||||||
|
#else
|
||||||
|
#include "l4d2_offsets_win32.h"
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
int maxplayers_offs = 136; // m_nMaxClientsLimit (in CGameServer::SetMaxClients)
|
||||||
|
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
||||||
|
#include "l4d1_offsets_linux.h"
|
||||||
|
#else
|
||||||
|
#include "l4d2_offsets_linux.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //_INCLUDE_GAME_OFFSETS_
|
@ -1,18 +0,0 @@
|
|||||||
#ifndef _INCLUDE_GAME_SIGNATURE_
|
|
||||||
#define _INCLUDE_GAME_SIGNATURE_
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
#include "l4d1_signature_win32.h"
|
|
||||||
#else
|
|
||||||
#include "l4d2_signature_win32.h"
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
#include "l4d1_signature_linux.h"
|
|
||||||
#else
|
|
||||||
#include "l4d2_signature_linux.h"
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //_INCLUDE_GAME_SIGNATURE_
|
|
9
l4d1_offsets_linux.h
Normal file
9
l4d1_offsets_linux.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _INCLUDE_L4D1_OFFSETS_LINUX_
|
||||||
|
#define _INCLUDE_L4D1_OFFSETS_LINUX_
|
||||||
|
|
||||||
|
const char* engine_dll = "engine.so";
|
||||||
|
int slots_offs = 94; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
|
||||||
|
int reservation_idx = 61; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
|
||||||
|
int maxhuman_idx = 132; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||||
|
|
||||||
|
#endif //_INCLUDE_L4D1_OFFSETS_LINUX_
|
9
l4d1_offsets_win32.h
Normal file
9
l4d1_offsets_win32.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _INCLUDE_L4D1_OFFSETS_WIN32_
|
||||||
|
#define _INCLUDE_L4D1_OFFSETS_WIN32_
|
||||||
|
|
||||||
|
int sv_offs = 6; // IServer pointer (in IVEngineServer::CreateFakeClient)
|
||||||
|
int slots_offs = 95; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
|
||||||
|
int reservation_idx = 60; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
|
||||||
|
int maxhuman_idx = 131; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||||
|
|
||||||
|
#endif //_INCLUDE_L4D1_OFFSETS_WIN32_
|
@ -1,57 +0,0 @@
|
|||||||
#ifndef _INCLUDE_L4D1_SIGNATURE_LINUX_
|
|
||||||
#define _INCLUDE_L4D1_SIGNATURE_LINUX_
|
|
||||||
|
|
||||||
const char* server_dll[] = {"server.so", 0};
|
|
||||||
const char* engine_dll[] = {"engine.so", 0};
|
|
||||||
const char* matchmaking_dll[] = {"matchmaking_ds.so", "matchmaking.so", 0};
|
|
||||||
|
|
||||||
//CBaseServer::GetMaxHumanPlayers(void)const
|
|
||||||
//function is in engine.so
|
|
||||||
const char* friends_lobby = "\x0F\x53\x83\xEC\x18\xE8\xC3\xC3\xC3\xC3\x81\xC3\xB9\xB8\x23\x00";
|
|
||||||
unsigned char friends_lobby_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
|
||||||
void* friends_lobby_org = NULL;
|
|
||||||
|
|
||||||
//CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int, CUtlVector<CLC_SplitPlayerConnect, CUtlMemory<CLC_SplitPlayerConnect, int>> &, bool)
|
|
||||||
//function is in engine.so, loc jz/jnz, above #Valve_Reject_Hidden_Game
|
|
||||||
const char* lobby_sux = "\x0A\x8B\xAE\x78\x01\x00\x00\x85\xED\x0F\x85";
|
|
||||||
const char* lobby_sux_new = "\x06\x00\xB8\x01\x00\x00\x00\x90";
|
|
||||||
void* lobby_sux_org = NULL;
|
|
||||||
|
|
||||||
//CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int, CUtlVector<CLC_SplitPlayerConnect, CUtlMemory<CLC_SplitPlayerConnect, int>> &, bool)
|
|
||||||
//function is in engine.so, above #Valve_Reject_Server_Full
|
|
||||||
const char* max_players = "\x0F\xFF\x50\xC3\x29\xC7\x01\xFD\x3B\xC3\xC3\xC3\x00\x00\x0F\x8E";
|
|
||||||
unsigned char max_players_new[]= {0x06, 0x07, 0x83, 0xFF, 0x3C, 0x90, 0x90, 0x90};
|
|
||||||
void* max_players_org = NULL;
|
|
||||||
|
|
||||||
//CServerGameClients::GetMaxHumanPlayers(void)
|
|
||||||
//function is in server.so
|
|
||||||
const char* server_bplayers = "\x1F\x53\x83\xEC\xC3\xE8\xC3\xC3\xC3\xC3\x81\xC3\xC3\xC3\xC3\xC3\x8B\x83\xC3\xC3\xC3\xC3\x8B\x00\x85\xC0\x74\x10\x8B\x10\x89\x04";
|
|
||||||
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
|
||||||
void* server_bplayers_org = NULL;
|
|
||||||
|
|
||||||
//CTerrorGameRules::ClientConnected(edict_t *, char const*, char const*, char *, int)
|
|
||||||
//function is in server.so
|
|
||||||
const char* human_limit = "\x12\x8B\x00\xC3\xC3\x24\x40\x89\x14\xC3\xFF\x90\xC3\x02\x00\x00\x39\xF0\x7E";
|
|
||||||
const char* human_limit_new = "\x02\x11\x90\x90";
|
|
||||||
void* human_limit_org = NULL;
|
|
||||||
|
|
||||||
//CGameServer::SetMaxClients(int)
|
|
||||||
//function is in engine.so
|
|
||||||
const char* players = "\x13\x83\xBB\xC3\xC3\xC3\xC3\x01\x7F\xC3\x8B\x80\x0C\xC3\xC3\x00\x89\xC3\xC3\xE8";
|
|
||||||
const char* players_new = "\x03\x1D\x89\xC2\xEB";
|
|
||||||
void* players_org = NULL;
|
|
||||||
|
|
||||||
//CBaseServer::SetReservationCookie(unsigned long long, char const*, ...)
|
|
||||||
//function in engine.so
|
|
||||||
const char* unreserved = "\x15\x55\x57\x56\x53\x81\xEC\x3C\x01\x00\x00\xE8\xC3\xC3\xC3\xC3\x81\xC3\x33\x8E\x23\x00";
|
|
||||||
const char* unreserved_new = "\x01\x00\xC3";
|
|
||||||
void* unreserved_org = NULL;
|
|
||||||
|
|
||||||
//CMatchTitle::GetTotalNumPlayersSupported(void)
|
|
||||||
//function in matchmaking_ds.so
|
|
||||||
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
|
|
||||||
unsigned char lobby_match_new[] = {0x01, 0x02, 0xC3};
|
|
||||||
void* lobby_match_org = NULL;
|
|
||||||
|
|
||||||
#endif //_INCLUDE_L4D1_SIGNATURE_LINUX_
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
|||||||
#ifndef _INCLUDE_L4D1_SIGNATURE_WIN32_
|
|
||||||
#define _INCLUDE_L4D1_SIGNATURE_WIN32_
|
|
||||||
|
|
||||||
const char* server_dll[] = {"server.dll", 0};
|
|
||||||
const char* engine_dll[] = {"engine.dll", 0};
|
|
||||||
const char* matchmaking_dll[] = {"matchmaking_ds.dll", "matchmaking.dll", 0};
|
|
||||||
|
|
||||||
const char* friends_lobby = "\x12\x56\x8B\xF1\x8B\x0D\xC3\xC3\xC3\xC3\x85\xC9\x74\xC3\x8B\x01\x8B\x50\x48";
|
|
||||||
unsigned char friends_lobby_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
|
||||||
void* friends_lobby_org = NULL;
|
|
||||||
|
|
||||||
const char* max_players = "\x28\x83\xBE\xC3\xC3\x00\x00\x00\x74\xC3\x8B\x54\xC3\xC3\x8B\x06\x8B\x7A\xC3\x8B\x50\x10\x8B\xCE\xFF\xD2\x2B\xF8\x8B\x06\x8B\x50\x08\x8B\xCE\xFF\xD2\x03\xC7\x3B\x86";
|
|
||||||
unsigned char max_players_new[]= {0x06, 0x26, 0x83, 0xF8, 0x3C, 0x90, 0x90, 0x90};
|
|
||||||
void* max_players_org = NULL;
|
|
||||||
|
|
||||||
const char* lobby_sux_new = "\x02\x07\x90\x90";
|
|
||||||
void* lobby_sux_org = NULL;
|
|
||||||
|
|
||||||
const char* server_bplayers = "\x1D\x56\x8B\xF1\xE8\xC3\xC3\xC3\xC3\x8B\x4C\x24\x08\x89\x01\x8B\x0D\xC3\xC3\xC3\xC3\x85\xC9\x74\xC3\x8B\x11\x8B\x42\x48";
|
|
||||||
unsigned char server_bplayers_new[] = {0x05, 0x1A, 0xB8, 0x3C, 0x00, 0x00, 0x00};
|
|
||||||
void* server_bplayers_org = NULL;
|
|
||||||
|
|
||||||
const char* human_limit = "\x15\x8B\x13\x8B\x82\xC3\xC3\x00\x00\x8B\xCB\xFF\xD0\x3B\xF8\x7C\xC3\x8B\xC3\xC3\xC3\x8B";
|
|
||||||
const char* human_limit_new = "\x01\x0E\xEB";
|
|
||||||
void* human_limit_org = NULL;
|
|
||||||
|
|
||||||
const char* players = "\x10\x56\x8B\xF1\x8B\x86\xC3\x02\x00\x00\x8B\x4C\x24\x08\x3B\xC8\x7F";
|
|
||||||
const char* players_new = "\x02\x0F\x90\x90";
|
|
||||||
void* players_org = NULL;
|
|
||||||
|
|
||||||
const char* unreserved = "\x1E\x81\xEC\xC3\xC3\x00\x00\x55\x8B\xAC\xC3\xC3\xC3\x00\x00\x56\x8B\xB4\xC3\xC3\xC3\x00\x00\x57\x8B\xBC\xC3\xC3\xC3\x00\x00";
|
|
||||||
const char* unreserved_new = "\x01\x00\xC3";
|
|
||||||
void* unreserved_org = NULL;
|
|
||||||
|
|
||||||
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
|
|
||||||
unsigned char lobby_match_new[] = {0x01, 0x01, 0xC3};
|
|
||||||
void* lobby_match_org = NULL;
|
|
||||||
|
|
||||||
#endif //_INCLUDE_L4D1_SIGNATURE_WIN32_
|
|
||||||
|
|
9
l4d2_offsets_linux.h
Normal file
9
l4d2_offsets_linux.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _INCLUDE_L4D2_OFFSETS_LINUX_
|
||||||
|
#define _INCLUDE_L4D2_OFFSETS_LINUX_
|
||||||
|
|
||||||
|
const char* engine_dll = "engine_srv.so";
|
||||||
|
int slots_offs = 95; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
|
||||||
|
int reservation_idx = 62; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
|
||||||
|
int maxhuman_idx = 137; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||||
|
|
||||||
|
#endif //_INCLUDE_L4D2_OFFSETS_LINUX_
|
9
l4d2_offsets_win32.h
Normal file
9
l4d2_offsets_win32.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _INCLUDE_L4D2_OFFSETS_WIN32_
|
||||||
|
#define _INCLUDE_L4D2_OFFSETS_WIN32_
|
||||||
|
|
||||||
|
int sv_offs = 8; // IServer pointer (in IVEngineServer::CreateFakeClient)
|
||||||
|
int slots_offs = 96; // m_numGameSlots (in CGameServer::ExecGameTypeCfg)
|
||||||
|
int reservation_idx = 61; // CBaseServer::ReplyReservationRequest(netadr_s&, bf_read&) vtable
|
||||||
|
int maxhuman_idx = 136; // CTerrorGameRules::GetMaxHumanPlayers vtable
|
||||||
|
|
||||||
|
#endif //_INCLUDE_L4D2_OFFSETS_WIN32_
|
@ -1,33 +0,0 @@
|
|||||||
#ifndef _INCLUDE_L4D2_SIGNATURE_LINUX_
|
|
||||||
#define _INCLUDE_L4D2_SIGNATURE_LINUX_
|
|
||||||
|
|
||||||
const char* server_dll[] = {"server_srv.so", "server.so", 0};
|
|
||||||
const char* engine_dll[] = {"engine_srv.so", "engine.so", 0};
|
|
||||||
const char* matchmaking_dll[] = {"matchmaking_ds_srv.so", "matchmaking_srv.so", "matchmaking_ds.so", "matchmaking.so", 0};
|
|
||||||
|
|
||||||
const char* lobby_sux = "\x13\xFF\x50\xC3\x84\xC0\x0F\x84\xC3\xC3\xC3\xC3\x8B\x87\xC3\x01\x00\x00\x85\xC0";
|
|
||||||
const char* lobby_sux_new = "\x06\x0B\xBE\x01\x00\x00\x00\x90";
|
|
||||||
void *lobby_sux_org = NULL;
|
|
||||||
|
|
||||||
const char* max_players = "\x15\x89\xC6\x8B\x07\x89\x3C\x24\xFF\x50\xC3\x29\xC6\x01\xF3\x3B\x9F\xC3\x01\x00\x00\x0F";
|
|
||||||
unsigned char max_players_new[]= {0x06, 0x0E, 0x83, 0xFB, 0x3C, 0x90, 0x90, 0x90};
|
|
||||||
void *max_players_org = NULL;
|
|
||||||
|
|
||||||
const char* server_bplayers = "\x16\x55\x89\xE5\x83\xEC\x08\xE8\xC3\xC3\xC3\xC3\xC9\x3C\x01\x19\xC0\x83\xE0\xFC\x83\xC0\x08";
|
|
||||||
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
|
||||||
void *server_bplayers_org = NULL;
|
|
||||||
|
|
||||||
const char* players = "\x23\x55\x89\xE5\x53\x83\xEC\xC3\x8B\x5D\x08\x8B\x55\x0C\x8B\x83\xC3\xC3\x00\x00\x39\xD0\x7C\x0B\x8B\x83\xC3\xC3\x00\x00\x39\xC2\x0F\x4D\xC2\x8B";
|
|
||||||
const char* players_new = "\x03\x13\x89\xD0\xEB";
|
|
||||||
void *players_org = NULL;
|
|
||||||
|
|
||||||
const char* unreserved = "\x0F\x55\x89\xE5\x57\x56\x53\x81\xEC\x3C\x01\x00\x00\x8B\x5D\x08";
|
|
||||||
const char* unreserved_new = "\x01\x00\xC3";
|
|
||||||
void *unreserved_org = NULL;
|
|
||||||
|
|
||||||
const char* lobby_match = "\x0A\x55\xB8\x08\x00\x00\x00\x89\xE5\x5D\xC3";
|
|
||||||
unsigned char lobby_match_new[] = {0x01, 0x02, 0xC3};
|
|
||||||
void *lobby_match_org = NULL;
|
|
||||||
|
|
||||||
#endif //_INCLUDE_L4D2_SIGNATURE_LINUX_
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
|||||||
#ifndef _INCLUDE_L4D2_SIGNATURE_WIN32_
|
|
||||||
#define _INCLUDE_L4D2_SIGNATURE_WIN32_
|
|
||||||
|
|
||||||
const char* server_dll[] = {"server.dll", 0};
|
|
||||||
const char* engine_dll[] = {"engine.dll", 0};
|
|
||||||
const char* matchmaking_dll[] = {"matchmaking_ds.dll", "matchmaking.dll", 0};
|
|
||||||
|
|
||||||
const char* max_players = "\x27\x83\xBE\xC3\xC3\x00\x00\x00\x74\xC3\x8B\xC3\xC3\x8B\x06\x8B\x7A\xC3\x8B\x50\x10\x8B\xCE\xFF\xD2\x2B\xF8\x8B\x06\x8B\x50\x08\x8B\xCE\xFF\xD2\x03\xC7\x3B\x86";
|
|
||||||
unsigned char max_players_new[]= {0x06, 0x25, 0x83, 0xF8, 0x3C, 0x90, 0x90, 0x90};
|
|
||||||
void* max_players_org = NULL;
|
|
||||||
|
|
||||||
const char* lobby_sux_new = "\x02\x07\x90\x90";
|
|
||||||
void* lobby_sux_org = NULL;
|
|
||||||
|
|
||||||
const char* server_bplayers = "\x36\xF7\x05\xC3\xC3\xC3\xC3\x00\x10\x00\x00\x74\x07\xB8\xC3\xC3\xC3\xC3\xEB\x11\xA1\xC3\xC3\xC3\xC3\x8B\x40\x24\x85\xC0\x75\x05\xB8\xC3\xC3\xC3\xC3\x8B\x0D\xC3\xC3\xC3\xC3\x8B\x11\x50\x8B\x42\x10\xFF\xD0\x85\xC0\x74\x17";
|
|
||||||
unsigned char server_bplayers_new[] = {0x06, 0x00, 0xB8, 0x3C, 0x00, 0x00, 0x00, 0xC3};
|
|
||||||
void* server_bplayers_org = NULL;
|
|
||||||
|
|
||||||
const char* players = "\x0F\x56\x8B\xF1\x8B\x86\xC3\x02\x00\x00\x8B\x4D\xC3\x3B\xC8\x7F";
|
|
||||||
const char* players_new = "\x02\x0E\x90\x90";
|
|
||||||
void* players_org = NULL;
|
|
||||||
|
|
||||||
const char* unreserved = "\x21\x55\x8B\xEC\x81\xEC\xC3\xC3\x00\x00\xA1\xC3\xC3\xC3\xC3\x33\xC5\x89\xC3\xC3\x53\x8B\xC3\xC3\x56\x8B\xC3\xC3\x57\x8B\xC3\xC3\x3B\xBE";
|
|
||||||
const char* unreserved_new = "\x01\x00\xC3";
|
|
||||||
void* unreserved_org = NULL;
|
|
||||||
|
|
||||||
const char* lobby_match = "\x06\xB8\x08\x00\x00\x00\xC3";
|
|
||||||
unsigned char lobby_match_new[] = {0x01, 0x01, 0xC3};
|
|
||||||
void* lobby_match_org = NULL;
|
|
||||||
|
|
||||||
#endif //_INCLUDE_L4D2_SIGNATURE_WIN32_
|
|
||||||
|
|
297
l4dtoolz_mm.cpp
297
l4dtoolz_mm.cpp
@ -1,166 +1,123 @@
|
|||||||
#include "l4dtoolz_mm.h"
|
#include "l4dtoolz_mm.h"
|
||||||
#include "signature.h"
|
#include "game_offsets.h"
|
||||||
#include "game_signature.h"
|
#include "memutils.h"
|
||||||
#include "icommandline.h"
|
#include "icommandline.h"
|
||||||
|
#include "server_class.h"
|
||||||
|
#include "sourcehook.h"
|
||||||
|
#include "matchmaking/imatchframework.h"
|
||||||
|
|
||||||
l4dtoolz g_l4dtoolz;
|
l4dtoolz g_l4dtoolz;
|
||||||
|
IServerGameDLL* gamedll = NULL;
|
||||||
|
IServerGameClients* gameclients = NULL;
|
||||||
IVEngineServer* engine = NULL;
|
IVEngineServer* engine = NULL;
|
||||||
|
IMatchFramework* g_pMatchFramework = NULL;
|
||||||
ICvar* g_pCVar = NULL;
|
ICvar* g_pCVar = NULL;
|
||||||
|
IServer* g_pGameIServer = NULL;
|
||||||
|
void* g_pGameRules = nullptr;
|
||||||
|
int m_numGameSlots = -1;
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
SH_DECL_HOOK1_void(IServerGameDLL, ApplyGameSettings, SH_NOATTRIB, 0, KeyValues*);
|
||||||
void* l4dtoolz::max_players_friend_lobby = NULL;
|
SH_DECL_HOOK0(IMatchTitle, GetTotalNumPlayersSupported, SH_NOATTRIB, 0, int);
|
||||||
void* l4dtoolz::chuman_limit = NULL;
|
SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, char const *, char const *, char const *, char const *, bool, bool);
|
||||||
#endif
|
SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, 0);
|
||||||
|
SH_DECL_MANUALHOOK0(CTerrorGameRules_GetMaxHumanPlayers, maxhuman_idx, 0, 0, int);
|
||||||
void* l4dtoolz::max_players_connect = NULL;
|
SH_DECL_MANUALHOOK2_void(CBaseServer_ReplyReservationRequest, reservation_idx, 0, 0, netadr_s&, CBitRead&);
|
||||||
void* l4dtoolz::max_players_server_browser = NULL;
|
|
||||||
void* l4dtoolz::lobby_sux_ptr = NULL;
|
|
||||||
void* l4dtoolz::tmp_player = NULL;
|
|
||||||
void* l4dtoolz::unreserved_ptr = NULL;
|
|
||||||
void* l4dtoolz::lobby_match_ptr = NULL;
|
|
||||||
|
|
||||||
ConVar sv_maxplayers("sv_maxplayers", "-1", 0, "Max Human Players", true, -1, true, 32, l4dtoolz::OnChangeMaxplayers);
|
ConVar sv_maxplayers("sv_maxplayers", "-1", 0, "Max Human Players", true, -1, true, 32, l4dtoolz::OnChangeMaxplayers);
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
ConVar sv_removehumanlimit("sv_removehumanlimit", "0", 0, "Remove Human limit reached kick", true, 0, true, 1, l4dtoolz::OnChangeRemovehumanlimit);
|
|
||||||
#endif
|
|
||||||
ConVar sv_force_unreserved("sv_force_unreserved", "0", 0, "Disallow lobby reservation cookie", true, 0, true, 1, l4dtoolz::OnChangeUnreserved);
|
ConVar sv_force_unreserved("sv_force_unreserved", "0", 0, "Disallow lobby reservation cookie", true, 0, true, 1, l4dtoolz::OnChangeUnreserved);
|
||||||
|
|
||||||
void l4dtoolz::OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue )
|
void l4dtoolz::OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue )
|
||||||
{
|
{
|
||||||
int new_value = ((ConVar*)var)->GetInt();
|
int new_value = ((ConVar*)var)->GetInt();
|
||||||
int old_value = atoi(pOldValue);
|
int old_value = atoi(pOldValue);
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
if (g_pGameIServer == NULL) {
|
||||||
if (max_players_friend_lobby == NULL || max_players_connect == NULL || max_players_server_browser == NULL || lobby_sux_ptr == NULL) {
|
Msg("g_pGameIServer pointer is not available\n");
|
||||||
#else
|
|
||||||
if (max_players_connect == NULL || max_players_server_browser == NULL || lobby_sux_ptr == NULL) {
|
|
||||||
#endif
|
|
||||||
Msg("sv_maxplayers init error\n");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(new_value != old_value) {
|
if(new_value != old_value) {
|
||||||
if(new_value >= 0) {
|
if(new_value >= 0) {
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
m_numGameSlots = new_value;
|
||||||
max_players_new[4] = friends_lobby_new[3] = server_bplayers_new[3] = (unsigned char)new_value;
|
*(int*)(((uint**)g_pGameIServer)+slots_offs) = m_numGameSlots;
|
||||||
#else
|
|
||||||
max_players_new[4] = server_bplayers_new[3] = (unsigned char)new_value;
|
|
||||||
#endif
|
|
||||||
if(lobby_match_ptr) {
|
|
||||||
lobby_match_new[2] = (unsigned char)new_value;
|
|
||||||
write_signature(lobby_match_ptr, lobby_match_new);
|
|
||||||
} else {
|
|
||||||
Msg("sv_maxplayers MS init error\n");
|
|
||||||
}
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
write_signature(max_players_friend_lobby, friends_lobby_new);
|
|
||||||
#endif
|
|
||||||
write_signature(max_players_connect, max_players_new);
|
|
||||||
write_signature(lobby_sux_ptr, lobby_sux_new);
|
|
||||||
write_signature(max_players_server_browser, server_bplayers_new);
|
|
||||||
} else {
|
} else {
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
m_numGameSlots = -1;
|
||||||
write_signature(max_players_friend_lobby, friends_lobby_org);
|
|
||||||
#endif
|
|
||||||
write_signature(max_players_connect, max_players_org);
|
|
||||||
write_signature(lobby_sux_ptr, lobby_sux_org);
|
|
||||||
write_signature(max_players_server_browser, server_bplayers_org);
|
|
||||||
|
|
||||||
if(lobby_match_ptr)
|
|
||||||
write_signature(lobby_match_ptr, lobby_match_org);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
void l4dtoolz::OnChangeRemovehumanlimit ( IConVar *var, const char *pOldValue, float flOldValue )
|
|
||||||
{
|
|
||||||
int new_value = ((ConVar*)var)->GetInt();
|
|
||||||
int old_value = atoi(pOldValue);
|
|
||||||
if(chuman_limit == NULL) {
|
|
||||||
Msg( "sv_removehumanlimit init error\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(new_value != old_value) {
|
|
||||||
if(new_value == 1) {
|
|
||||||
write_signature(chuman_limit, human_limit_new);
|
|
||||||
}else{
|
|
||||||
write_signature(chuman_limit, human_limit_org);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void l4dtoolz::OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue )
|
void l4dtoolz::OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue )
|
||||||
{
|
{
|
||||||
int new_value = ((ConVar*)var)->GetInt();
|
int new_value = ((ConVar*)var)->GetInt();
|
||||||
int old_value = atoi(pOldValue);
|
int old_value = atoi(pOldValue);
|
||||||
if(unreserved_ptr == NULL ) {
|
if (g_pGameIServer == NULL) {
|
||||||
Msg("unreserved_ptr init error\n");
|
Msg("g_pGameIServer pointer is not available\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(new_value != old_value) {
|
if(new_value != old_value) {
|
||||||
if(new_value == 1) {
|
if(new_value == 1) {
|
||||||
write_signature(unreserved_ptr, unreserved_new);
|
|
||||||
engine->ServerCommand("sv_allow_lobby_connect_only 0\n");
|
engine->ServerCommand("sv_allow_lobby_connect_only 0\n");
|
||||||
} else {
|
|
||||||
write_signature(unreserved_ptr, unreserved_org);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Hook_ApplyGameSettings(KeyValues *pKV)
|
||||||
|
{
|
||||||
|
if (!pKV) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_numGameSlots = sv_maxplayers.GetInt();
|
||||||
|
if (m_numGameSlots == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pKV->SetInt("members/numSlots", m_numGameSlots);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Hook_ReplyReservationRequest(netadr_s& adr, CBitRead& inmsg)
|
||||||
|
{
|
||||||
|
if (sv_force_unreserved.GetInt()) {
|
||||||
|
RETURN_META(MRES_SUPERCEDE);
|
||||||
|
}
|
||||||
|
RETURN_META(MRES_IGNORED);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Hook_GetMaxHumanPlayers()
|
||||||
|
{
|
||||||
|
if (m_numGameSlots > 0) {
|
||||||
|
RETURN_META_VALUE(MRES_SUPERCEDE, m_numGameSlots);
|
||||||
|
}
|
||||||
|
RETURN_META_VALUE(MRES_IGNORED, m_numGameSlots);
|
||||||
|
}
|
||||||
|
|
||||||
PLUGIN_EXPOSE(l4dtoolz, g_l4dtoolz);
|
PLUGIN_EXPOSE(l4dtoolz, g_l4dtoolz);
|
||||||
|
|
||||||
bool l4dtoolz::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
bool l4dtoolz::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
|
||||||
{
|
{
|
||||||
PLUGIN_SAVEVARS();
|
PLUGIN_SAVEVARS();
|
||||||
|
|
||||||
|
GET_V_IFACE_CURRENT(GetServerFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
|
||||||
|
GET_V_IFACE_CURRENT(GetServerFactory, gameclients, IServerGameClients, INTERFACEVERSION_SERVERGAMECLIENTS);
|
||||||
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
|
||||||
|
GET_V_IFACE_CURRENT(GetEngineFactory, g_pMatchFramework, IMatchFramework, IMATCHFRAMEWORK_VERSION_STRING);
|
||||||
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
|
GET_V_IFACE_CURRENT(GetEngineFactory, g_pCVar, ICvar, CVAR_INTERFACE_VERSION);
|
||||||
|
|
||||||
ConVar_Register(0, this);
|
void* handle = NULL;
|
||||||
|
#ifdef PLATFORM_WINDOWS
|
||||||
struct base_addr_t base_addr;
|
if (!(handle=SH_GET_ORIG_VFNPTR_ENTRY(engine, &IVEngineServer::CreateFakeClient))) {
|
||||||
base_addr.addr = NULL;
|
Warning("Failed to get address 'IVEngineServer::CreateFakeClient'\n");
|
||||||
base_addr.len = 0;
|
} else {
|
||||||
|
g_pGameIServer = *reinterpret_cast<IServer **>(reinterpret_cast<unsigned char *>(handle)+sv_offs);
|
||||||
find_base_from_list(matchmaking_dll, &base_addr);
|
|
||||||
|
|
||||||
if(!lobby_match_ptr) {
|
|
||||||
lobby_match_ptr = find_signature(lobby_match, &base_addr, 1);
|
|
||||||
get_original_signature(lobby_match_ptr, lobby_match_new, lobby_match_org);
|
|
||||||
}
|
|
||||||
|
|
||||||
find_base_from_list(engine_dll, &base_addr);
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
if(!max_players_friend_lobby) {
|
|
||||||
max_players_friend_lobby = find_signature(friends_lobby, &base_addr, 0);
|
|
||||||
get_original_signature(max_players_friend_lobby, friends_lobby_new, friends_lobby_org);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if(!max_players_connect) {
|
|
||||||
max_players_connect = find_signature(max_players, &base_addr, 0);
|
|
||||||
get_original_signature(max_players_connect, max_players_new, max_players_org);
|
|
||||||
}
|
|
||||||
if(!lobby_sux_ptr) {
|
|
||||||
#ifdef WIN32
|
|
||||||
lobby_sux_ptr = max_players_connect;
|
|
||||||
#else
|
#else
|
||||||
lobby_sux_ptr = find_signature(lobby_sux, &base_addr, 0);
|
if (!(handle=dlopen(engine_dll, RTLD_LAZY))) {
|
||||||
|
Warning("Could't open library '%s'\n", engine_dll);
|
||||||
|
} else {
|
||||||
|
g_pGameIServer = (IServer *)g_MemUtils.ResolveSymbol(handle, "sv");
|
||||||
|
dlclose(handle);
|
||||||
#endif
|
#endif
|
||||||
get_original_signature(lobby_sux_ptr, lobby_sux_new, lobby_sux_org);
|
int* m_nMaxClientsLimit = (int*)(((uint**)g_pGameIServer)+maxplayers_offs);
|
||||||
}
|
if (*m_nMaxClientsLimit != 0x12) {
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
Warning("Couldn't patch maxplayers\n");
|
||||||
#ifdef WIN32
|
g_pGameIServer = NULL;
|
||||||
if(!max_players_server_browser) {
|
} else {
|
||||||
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
|
*m_nMaxClientsLimit = 0x20;
|
||||||
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
if(!tmp_player) {
|
|
||||||
tmp_player = find_signature(players, &base_addr, 0);
|
|
||||||
if(tmp_player) {
|
|
||||||
get_original_signature(tmp_player, players_new, players_org);
|
|
||||||
write_signature(tmp_player, players_new);
|
|
||||||
const char *pszCmdLineMax;
|
const char *pszCmdLineMax;
|
||||||
if(CommandLine()->CheckParm("-maxplayers", &pszCmdLineMax) || CommandLine()->CheckParm("+maxplayers", &pszCmdLineMax)) {
|
if(CommandLine()->CheckParm("-maxplayers", &pszCmdLineMax) || CommandLine()->CheckParm("+maxplayers", &pszCmdLineMax)) {
|
||||||
char command[32];
|
char command[32];
|
||||||
@ -170,62 +127,75 @@ bool l4dtoolz::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
|
|||||||
engine->ServerCommand("maxplayers 31\n");
|
engine->ServerCommand("maxplayers 31\n");
|
||||||
}
|
}
|
||||||
engine->ServerExecute();
|
engine->ServerExecute();
|
||||||
write_signature(tmp_player, players_org);
|
|
||||||
free(players_org);
|
|
||||||
players_org = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!unreserved_ptr) {
|
|
||||||
unreserved_ptr = find_signature(unreserved, &base_addr, 0);
|
SH_ADD_HOOK(IServerGameDLL, ApplyGameSettings, gamedll, SH_STATIC(Hook_ApplyGameSettings), true);
|
||||||
get_original_signature(unreserved_ptr, unreserved_new, unreserved_org);
|
SH_ADD_HOOK(IMatchTitle, GetTotalNumPlayersSupported, g_pMatchFramework->GetMatchTitle(), SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||||
|
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &l4dtoolz::LevelInit, true);
|
||||||
|
SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &l4dtoolz::LevelShutdown, false);
|
||||||
|
|
||||||
|
if (g_pGameIServer) {
|
||||||
|
SH_ADD_MANUALHOOK(CBaseServer_ReplyReservationRequest, g_pGameIServer, SH_STATIC(Hook_ReplyReservationRequest), false);
|
||||||
|
} else {
|
||||||
|
Warning("g_pGameIServer pointer is not available\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
find_base_from_list(server_dll, &base_addr);
|
ConVar_Register(0, this);
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
if(!chuman_limit) {
|
|
||||||
chuman_limit = find_signature(human_limit, &base_addr, 0);
|
|
||||||
get_original_signature(chuman_limit, human_limit_new, human_limit_org);
|
|
||||||
}
|
|
||||||
#ifndef WIN32
|
|
||||||
if(!max_players_server_browser) {
|
|
||||||
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
|
|
||||||
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
if(!max_players_server_browser) {
|
|
||||||
max_players_server_browser = find_signature(server_bplayers, &base_addr, 0);
|
|
||||||
get_original_signature(max_players_server_browser, server_bplayers_new, server_bplayers_org);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool l4dtoolz::Unload(char *error, size_t maxlen)
|
bool l4dtoolz::Unload(char *error, size_t maxlen)
|
||||||
{
|
{
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
SH_REMOVE_HOOK(IServerGameDLL, ApplyGameSettings, gamedll, SH_STATIC(Hook_ApplyGameSettings), true);
|
||||||
write_signature(max_players_friend_lobby, friends_lobby_org);
|
SH_REMOVE_HOOK(IMatchTitle, GetTotalNumPlayersSupported, g_pMatchFramework->GetMatchTitle(), SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||||
write_signature(chuman_limit, human_limit_org);
|
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &l4dtoolz::LevelInit, true);
|
||||||
free(friends_lobby_org);
|
SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &l4dtoolz::LevelShutdown, false);
|
||||||
free(human_limit_org);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
write_signature(max_players_connect, max_players_org);
|
if (g_pGameIServer) {
|
||||||
write_signature(lobby_sux_ptr, lobby_sux_org);
|
SH_REMOVE_MANUALHOOK(CBaseServer_ReplyReservationRequest, g_pGameIServer, SH_STATIC(Hook_ReplyReservationRequest), false);
|
||||||
write_signature(max_players_server_browser, server_bplayers_org);
|
}
|
||||||
write_signature(unreserved_ptr, unreserved_org);
|
|
||||||
write_signature(lobby_match_ptr, lobby_match_org);
|
|
||||||
|
|
||||||
free(max_players_org);
|
LevelShutdown();
|
||||||
free(lobby_sux_org);
|
ConVar_Unregister();
|
||||||
free(server_bplayers_org);
|
|
||||||
free(unreserved_org);
|
|
||||||
free(lobby_match_org);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool l4dtoolz::LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
|
||||||
|
{
|
||||||
|
g_pGameRules = nullptr;
|
||||||
|
|
||||||
|
ServerClass *pServerClass = UTIL_FindServerClass("CTerrorGameRulesProxy");
|
||||||
|
if (pServerClass) {
|
||||||
|
int i, iCount;
|
||||||
|
iCount = pServerClass->m_pTable->GetNumProps();
|
||||||
|
for (i = 0; i < iCount; i++) {
|
||||||
|
if (stricmp(pServerClass->m_pTable->GetProp(i)->GetName(), "terror_gamerules_data") == 0) {
|
||||||
|
g_pGameRules = (*pServerClass->m_pTable->GetProp(i)->GetDataTableProxyFn())(NULL, NULL, NULL, NULL, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_pGameRules) {
|
||||||
|
SH_ADD_MANUALHOOK(CTerrorGameRules_GetMaxHumanPlayers, g_pGameRules, SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||||
|
} else {
|
||||||
|
Warning("g_pGameRules pointer is not available\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void l4dtoolz::LevelShutdown()
|
||||||
|
{
|
||||||
|
if (g_pGameRules) {
|
||||||
|
SH_REMOVE_MANUALHOOK(CTerrorGameRules_GetMaxHumanPlayers, g_pGameRules, SH_STATIC(Hook_GetMaxHumanPlayers), false);
|
||||||
|
g_pGameRules = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@ -243,6 +213,21 @@ size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ServerClass *UTIL_FindServerClass(const char *classname)
|
||||||
|
{
|
||||||
|
ServerClass *sc = gamedll->GetAllServerClasses();
|
||||||
|
while (sc)
|
||||||
|
{
|
||||||
|
if (strcmp(classname, sc->GetName()) == 0)
|
||||||
|
{
|
||||||
|
return sc;
|
||||||
|
}
|
||||||
|
sc = sc->m_pNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char *l4dtoolz::GetLicense()
|
const char *l4dtoolz::GetLicense()
|
||||||
{
|
{
|
||||||
return "GPLv3";
|
return "GPLv3";
|
||||||
@ -250,7 +235,7 @@ const char *l4dtoolz::GetLicense()
|
|||||||
|
|
||||||
const char *l4dtoolz::GetVersion()
|
const char *l4dtoolz::GetVersion()
|
||||||
{
|
{
|
||||||
return "1.1.0.2";
|
return "2.0.0";
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *l4dtoolz::GetDate()
|
const char *l4dtoolz::GetDate()
|
||||||
|
@ -8,6 +8,8 @@ class l4dtoolz : public ISmmPlugin, public IConCommandBaseAccessor
|
|||||||
public:
|
public:
|
||||||
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late);
|
||||||
bool Unload(char *error, size_t maxlen);
|
bool Unload(char *error, size_t maxlen);
|
||||||
|
bool LevelInit(const char *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background);
|
||||||
|
void LevelShutdown();
|
||||||
public:
|
public:
|
||||||
const char *GetAuthor();
|
const char *GetAuthor();
|
||||||
const char *GetName();
|
const char *GetName();
|
||||||
@ -20,25 +22,12 @@ public:
|
|||||||
public: //IConCommandBaseAccessor
|
public: //IConCommandBaseAccessor
|
||||||
bool RegisterConCommandBase(ConCommandBase *pVar);
|
bool RegisterConCommandBase(ConCommandBase *pVar);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue );
|
static void OnChangeMaxplayers ( IConVar *var, const char *pOldValue, float flOldValue );
|
||||||
static void OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue );
|
static void OnChangeUnreserved ( IConVar *var, const char *pOldValue, float flOldValue );
|
||||||
|
|
||||||
#if SOURCE_ENGINE == SE_LEFT4DEAD
|
|
||||||
static void OnChangeRemovehumanlimit ( IConVar *var, const char *pOldValue, float flOldValue );
|
|
||||||
static void* max_players_friend_lobby;
|
|
||||||
static void* chuman_limit;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void* max_players_connect;
|
|
||||||
static void* max_players_server_browser;
|
|
||||||
static void* lobby_sux_ptr;
|
|
||||||
static void* tmp_player;
|
|
||||||
static void* unreserved_ptr;
|
|
||||||
static void* lobby_match_ptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
|
||||||
|
ServerClass *UTIL_FindServerClass(const char *classname);
|
||||||
|
|
||||||
extern l4dtoolz g_l4dtoolz;
|
extern l4dtoolz g_l4dtoolz;
|
||||||
|
|
||||||
|
395
memutils.cpp
Normal file
395
memutils.cpp
Normal file
@ -0,0 +1,395 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* MemoryUtils
|
||||||
|
* Copyright (C) 2004-2011 AlliedModders LLC., 2011 Prodigysim
|
||||||
|
* All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, the authors give you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "memutils.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if SH_SYS == SH_SYS_LINUX
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <link.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#define PAGE_SIZE 4096
|
||||||
|
#define PAGE_ALIGN_UP(x) ((x + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))
|
||||||
|
#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
|
||||||
|
#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SH_SYS == SH_SYS_APPLE
|
||||||
|
#include <AvailabilityMacros.h>
|
||||||
|
#include <mach/task.h>
|
||||||
|
#include <mach-o/dyld_images.h>
|
||||||
|
#include <mach-o/loader.h>
|
||||||
|
#include <mach-o/nlist.h>
|
||||||
|
|
||||||
|
/* Define things from 10.6 SDK for older SDKs */
|
||||||
|
#ifndef MAC_OS_X_VERSION_10_6
|
||||||
|
struct task_dyld_info
|
||||||
|
{
|
||||||
|
mach_vm_address_t all_image_info_addr;
|
||||||
|
mach_vm_size_t all_image_info_size;
|
||||||
|
};
|
||||||
|
typedef struct task_dyld_info task_dyld_info_data_t;
|
||||||
|
#define TASK_DYLD_INFO 17
|
||||||
|
#define TASK_DYLD_INFO_COUNT (sizeof(task_dyld_info_data_t) / sizeof(natural_t))
|
||||||
|
#endif // MAC_OS_X_VERSION_10_6
|
||||||
|
#endif // SH_SYS_APPLE
|
||||||
|
|
||||||
|
MemoryUtils g_MemUtils;
|
||||||
|
|
||||||
|
MemoryUtils::MemoryUtils()
|
||||||
|
{
|
||||||
|
#if SH_SYS == SH_SYS_APPLE
|
||||||
|
|
||||||
|
Gestalt(gestaltSystemVersionMajor, &m_OSXMajor);
|
||||||
|
Gestalt(gestaltSystemVersionMinor, &m_OSXMinor);
|
||||||
|
|
||||||
|
/* Get pointer to struct that describes all loaded mach-o images in process */
|
||||||
|
if ((m_OSXMajor == 10 && m_OSXMinor >= 6) || m_OSXMajor > 10)
|
||||||
|
{
|
||||||
|
task_dyld_info_data_t dyld_info;
|
||||||
|
mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT;
|
||||||
|
task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &count);
|
||||||
|
m_ImageList = (struct dyld_all_image_infos *)dyld_info.all_image_info_addr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct nlist list[2];
|
||||||
|
memset(list, 0, sizeof(list));
|
||||||
|
list[0].n_un.n_name = (char *)"_dyld_all_image_infos";
|
||||||
|
nlist("/usr/lib/dyld", list);
|
||||||
|
m_ImageList = (struct dyld_all_image_infos *)list[0].n_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryUtils::~MemoryUtils()
|
||||||
|
{
|
||||||
|
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
delete m_SymTables[i];
|
||||||
|
}
|
||||||
|
m_SymTables.clear();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void *MemoryUtils::ResolveSymbol(void *handle, const char *symbol)
|
||||||
|
{
|
||||||
|
#if SH_SYS == SH_SYS_WIN32
|
||||||
|
|
||||||
|
return GetProcAddress((HMODULE)handle, symbol);
|
||||||
|
|
||||||
|
#elif SH_SYS == SH_SYS_LINUX
|
||||||
|
|
||||||
|
struct link_map *dlmap;
|
||||||
|
struct stat dlstat;
|
||||||
|
int dlfile;
|
||||||
|
uintptr_t map_base;
|
||||||
|
Elf32_Ehdr *file_hdr;
|
||||||
|
Elf32_Shdr *sections, *shstrtab_hdr, *symtab_hdr, *strtab_hdr;
|
||||||
|
Elf32_Sym *symtab;
|
||||||
|
const char *shstrtab, *strtab;
|
||||||
|
uint16_t section_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlmap = (struct link_map *)handle;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
strtab_hdr = NULL;
|
||||||
|
table = NULL;
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlmap->l_addr)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlmap->l_addr;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.push_back(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have open the actual library */
|
||||||
|
dlfile = open(dlmap->l_name, O_RDONLY);
|
||||||
|
if (dlfile == -1 || fstat(dlfile, &dlstat) == -1)
|
||||||
|
{
|
||||||
|
close(dlfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map library file into memory */
|
||||||
|
file_hdr = (Elf32_Ehdr *)mmap(NULL, dlstat.st_size, PROT_READ, MAP_PRIVATE, dlfile, 0);
|
||||||
|
map_base = (uintptr_t)file_hdr;
|
||||||
|
if (file_hdr == MAP_FAILED)
|
||||||
|
{
|
||||||
|
close(dlfile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
close(dlfile);
|
||||||
|
|
||||||
|
if (file_hdr->e_shoff == 0 || file_hdr->e_shstrndx == SHN_UNDEF)
|
||||||
|
{
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
sections = (Elf32_Shdr *)(map_base + file_hdr->e_shoff);
|
||||||
|
section_count = file_hdr->e_shnum;
|
||||||
|
/* Get ELF section header string table */
|
||||||
|
shstrtab_hdr = §ions[file_hdr->e_shstrndx];
|
||||||
|
shstrtab = (const char *)(map_base + shstrtab_hdr->sh_offset);
|
||||||
|
|
||||||
|
/* Iterate sections while looking for ELF symbol table and string table */
|
||||||
|
for (uint16_t i = 0; i < section_count; i++)
|
||||||
|
{
|
||||||
|
Elf32_Shdr &hdr = sections[i];
|
||||||
|
const char *section_name = shstrtab + hdr.sh_name;
|
||||||
|
|
||||||
|
if (strcmp(section_name, ".symtab") == 0)
|
||||||
|
{
|
||||||
|
symtab_hdr = &hdr;
|
||||||
|
}
|
||||||
|
else if (strcmp(section_name, ".strtab") == 0)
|
||||||
|
{
|
||||||
|
strtab_hdr = &hdr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Uh oh, we don't have a symbol table or a string table */
|
||||||
|
if (symtab_hdr == NULL || strtab_hdr == NULL)
|
||||||
|
{
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
symtab = (Elf32_Sym *)(map_base + symtab_hdr->sh_offset);
|
||||||
|
strtab = (const char *)(map_base + strtab_hdr->sh_offset);
|
||||||
|
symbol_count = symtab_hdr->sh_size / symtab_hdr->sh_entsize;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
Elf32_Sym &sym = symtab[i];
|
||||||
|
unsigned char sym_type = ELF32_ST_TYPE(sym.st_info);
|
||||||
|
const char *sym_name = strtab + sym.st_name;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined or do not refer to functions or objects */
|
||||||
|
if (sym.st_shndx == SHN_UNDEF || (sym_type != STT_FUNC && sym_type != STT_OBJECT))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlmap->l_addr + sym.st_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
munmap(file_hdr, dlstat.st_size);
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#elif SH_SYS == SH_SYS_APPLE
|
||||||
|
|
||||||
|
uintptr_t dlbase, linkedit_addr;
|
||||||
|
uint32_t image_count;
|
||||||
|
struct mach_header *file_hdr;
|
||||||
|
struct load_command *loadcmds;
|
||||||
|
struct segment_command *linkedit_hdr;
|
||||||
|
struct symtab_command *symtab_hdr;
|
||||||
|
struct nlist *symtab;
|
||||||
|
const char *strtab;
|
||||||
|
uint32_t loadcmd_count;
|
||||||
|
uint32_t symbol_count;
|
||||||
|
LibSymbolTable *libtable;
|
||||||
|
SymbolTable *table;
|
||||||
|
Symbol *symbol_entry;
|
||||||
|
|
||||||
|
dlbase = 0;
|
||||||
|
image_count = m_ImageList->infoArrayCount;
|
||||||
|
linkedit_hdr = NULL;
|
||||||
|
symtab_hdr = NULL;
|
||||||
|
table = NULL;
|
||||||
|
|
||||||
|
/* Loop through mach-o images in process.
|
||||||
|
* We can skip index 0 since that is just the executable.
|
||||||
|
*/
|
||||||
|
for (uint32_t i = 1; i < image_count; i++)
|
||||||
|
{
|
||||||
|
const struct dyld_image_info &info = m_ImageList->infoArray[i];
|
||||||
|
|
||||||
|
/* "Load" each one until we get a matching handle */
|
||||||
|
void *h = dlopen(info.imageFilePath, RTLD_NOLOAD);
|
||||||
|
if (h == handle)
|
||||||
|
{
|
||||||
|
dlbase = (uintptr_t)info.imageLoadAddress;
|
||||||
|
dlclose(h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
dlclose(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dlbase)
|
||||||
|
{
|
||||||
|
/* Uh oh, we couldn't find a matching handle */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if we already have a symbol table for this library */
|
||||||
|
for (size_t i = 0; i < m_SymTables.size(); i++)
|
||||||
|
{
|
||||||
|
libtable = m_SymTables[i];
|
||||||
|
if (libtable->lib_base == dlbase)
|
||||||
|
{
|
||||||
|
table = &libtable->table;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we don't have a symbol table for this library, then create one */
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
libtable = new LibSymbolTable();
|
||||||
|
libtable->table.Initialize();
|
||||||
|
libtable->lib_base = dlbase;
|
||||||
|
libtable->last_pos = 0;
|
||||||
|
table = &libtable->table;
|
||||||
|
m_SymTables.push_back(libtable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See if the symbol is already cached in our table */
|
||||||
|
symbol_entry = table->FindSymbol(symbol, strlen(symbol));
|
||||||
|
if (symbol_entry != NULL)
|
||||||
|
{
|
||||||
|
return symbol_entry->address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If symbol isn't in our table, then we have to locate it in memory */
|
||||||
|
|
||||||
|
file_hdr = (struct mach_header *)dlbase;
|
||||||
|
loadcmds = (struct load_command *)(dlbase + sizeof(struct mach_header));
|
||||||
|
loadcmd_count = file_hdr->ncmds;
|
||||||
|
|
||||||
|
/* Loop through load commands until we find the ones for the symbol table */
|
||||||
|
for (uint32_t i = 0; i < loadcmd_count; i++)
|
||||||
|
{
|
||||||
|
if (loadcmds->cmd == LC_SEGMENT && !linkedit_hdr)
|
||||||
|
{
|
||||||
|
struct segment_command *seg = (struct segment_command *)loadcmds;
|
||||||
|
if (strcmp(seg->segname, "__LINKEDIT") == 0)
|
||||||
|
{
|
||||||
|
linkedit_hdr = seg;
|
||||||
|
if (symtab_hdr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (loadcmds->cmd == LC_SYMTAB)
|
||||||
|
{
|
||||||
|
symtab_hdr = (struct symtab_command *)loadcmds;
|
||||||
|
if (linkedit_hdr)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load commands are not of a fixed size which is why we add the size */
|
||||||
|
loadcmds = (struct load_command *)((uintptr_t)loadcmds + loadcmds->cmdsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!linkedit_hdr || !symtab_hdr || !symtab_hdr->symoff || !symtab_hdr->stroff)
|
||||||
|
{
|
||||||
|
/* Uh oh, no symbol table */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedit_addr = dlbase + linkedit_hdr->vmaddr;
|
||||||
|
symtab = (struct nlist *)(linkedit_addr + symtab_hdr->symoff - linkedit_hdr->fileoff);
|
||||||
|
strtab = (const char *)(linkedit_addr + symtab_hdr->stroff - linkedit_hdr->fileoff);
|
||||||
|
symbol_count = symtab_hdr->nsyms;
|
||||||
|
|
||||||
|
/* Iterate symbol table starting from the position we were at last time */
|
||||||
|
for (uint32_t i = libtable->last_pos; i < symbol_count; i++)
|
||||||
|
{
|
||||||
|
struct nlist &sym = symtab[i];
|
||||||
|
/* Ignore the prepended underscore on all symbols, so +1 here */
|
||||||
|
const char *sym_name = strtab + sym.n_un.n_strx + 1;
|
||||||
|
Symbol *cur_sym;
|
||||||
|
|
||||||
|
/* Skip symbols that are undefined */
|
||||||
|
if (sym.n_sect == NO_SECT)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Caching symbols as we go along */
|
||||||
|
cur_sym = table->InternSymbol(sym_name, strlen(sym_name), (void *)(dlbase + sym.n_value));
|
||||||
|
if (strcmp(symbol, sym_name) == 0)
|
||||||
|
{
|
||||||
|
symbol_entry = cur_sym;
|
||||||
|
libtable->last_pos = ++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return symbol_entry ? symbol_entry->address : NULL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
return NULL;
|
||||||
|
}
|
79
memutils.h
Normal file
79
memutils.h
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* MemoryUtils
|
||||||
|
* Copyright (C) 2004-2011 AlliedModders LLC., 2011 ProdigySim
|
||||||
|
* All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, the authors give you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "sourcehook.h"
|
||||||
|
#include "sh_memory.h"
|
||||||
|
|
||||||
|
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||||
|
#include <sh_vector.h>
|
||||||
|
#include "sm_symtable.h"
|
||||||
|
using SourceHook::CVector;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SH_SYS == SH_SYS_APPLE
|
||||||
|
#include <CoreServices/CoreServices.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||||
|
struct LibSymbolTable
|
||||||
|
{
|
||||||
|
SymbolTable table;
|
||||||
|
uintptr_t lib_base;
|
||||||
|
uint32_t last_pos;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class MemoryUtils
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MemoryUtils();
|
||||||
|
~MemoryUtils();
|
||||||
|
void *ResolveSymbol(void *handle, const char *symbol);
|
||||||
|
|
||||||
|
#if SH_SYS == SH_SYS_LINUX || SH_SYS == SH_SYS_APPLE
|
||||||
|
private:
|
||||||
|
CVector<LibSymbolTable *> m_SymTables;
|
||||||
|
#if SH_SYS == SH_SYS_APPLE
|
||||||
|
struct dyld_all_image_infos *m_ImageList;
|
||||||
|
SInt32 m_OSXMajor;
|
||||||
|
SInt32 m_OSXMinor;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
extern MemoryUtils g_MemUtils;
|
||||||
|
|
||||||
|
#endif // _INCLUDE_SOURCEMOD_MEMORYUTILS_H_
|
243
signature.cpp
243
signature.cpp
@ -1,243 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include "signature.h"
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#include <TlHelp32.h>
|
|
||||||
#else
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <link.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SIGN_HEADER_LEN 2
|
|
||||||
#define SIGN_LEN_BYTE 0
|
|
||||||
#define SIGN_OFFSET_BYTE 1
|
|
||||||
|
|
||||||
|
|
||||||
static int lock_region(const void *addr, unsigned int sign_len, unsigned int sign_off, int lock)
|
|
||||||
{
|
|
||||||
#ifndef WIN32
|
|
||||||
unsigned int all_adr;
|
|
||||||
unsigned int all_size;
|
|
||||||
unsigned int p_size;
|
|
||||||
unsigned int u_addr;
|
|
||||||
|
|
||||||
p_size = sysconf(_SC_PAGESIZE);
|
|
||||||
u_addr = (unsigned int)addr;
|
|
||||||
|
|
||||||
all_adr = (u_addr + sign_off) & ~(p_size-1);
|
|
||||||
all_size = u_addr - all_adr + sign_len;
|
|
||||||
|
|
||||||
if(lock) {
|
|
||||||
mlock((void *)all_adr, all_size);
|
|
||||||
mprotect((void *)all_adr, all_size, PROT_READ|PROT_WRITE|PROT_EXEC);
|
|
||||||
} else
|
|
||||||
munlock((void *)all_adr, all_size);
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void *find_signature(const char* mask, struct base_addr_t *base_addr, int pure)
|
|
||||||
{
|
|
||||||
char *pBasePtr = (char *)base_addr->addr;
|
|
||||||
char *pEndPtr = pBasePtr+base_addr->len-(int)mask[SIGN_LEN_BYTE];
|
|
||||||
int i;
|
|
||||||
char* tmp;
|
|
||||||
if(base_addr->addr == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
unsigned int p_size = sysconf(_SC_PAGESIZE);
|
|
||||||
char* all_adr = (char*)((unsigned int)pBasePtr & ~(p_size-1));
|
|
||||||
unsigned int size = pEndPtr - all_adr;
|
|
||||||
mlock(all_adr, size);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
while(pBasePtr < pEndPtr)
|
|
||||||
{
|
|
||||||
tmp = pBasePtr;
|
|
||||||
|
|
||||||
for(i = 1; i <= mask[SIGN_LEN_BYTE]; ++i) {
|
|
||||||
if(!pure && mask[i] == '\xC3'){
|
|
||||||
tmp++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(mask[i] != *tmp ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tmp++;
|
|
||||||
}
|
|
||||||
if(i-1 == mask[0]) {
|
|
||||||
#ifndef WIN32
|
|
||||||
munlock(all_adr, size);
|
|
||||||
#endif
|
|
||||||
return pBasePtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
pBasePtr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
munlock(all_adr, size);
|
|
||||||
#endif
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef WIN32
|
|
||||||
struct v_data{
|
|
||||||
const char *fname;
|
|
||||||
void *baddr;
|
|
||||||
unsigned int blen;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int callback(struct dl_phdr_info *info, size_t size, void *data)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
const char* filename;
|
|
||||||
|
|
||||||
if (!info->dlpi_name || !info->dlpi_name[0])
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
filename = ((struct v_data *)data)->fname;
|
|
||||||
|
|
||||||
if(strstr(info->dlpi_name, filename)) {
|
|
||||||
if(strstr( info->dlpi_name, "metamod") == NULL) {
|
|
||||||
((struct v_data *)data)->baddr = (void*)info->dlpi_addr;
|
|
||||||
((struct v_data *)data)->blen = 0;
|
|
||||||
for(i = 0; i < info->dlpi_phnum; ++i) {
|
|
||||||
((struct v_data *)data)->blen+=info->dlpi_phdr[i].p_filesz;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int find_base(const char* name, struct base_addr_t *base_addr)
|
|
||||||
{
|
|
||||||
#ifdef WIN32
|
|
||||||
MODULEENTRY32 modent;
|
|
||||||
HANDLE hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
|
|
||||||
if(hModuleSnap == INVALID_HANDLE_VALUE) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
modent.dwSize = sizeof(MODULEENTRY32);
|
|
||||||
|
|
||||||
if(!Module32Next(hModuleSnap, &modent)){
|
|
||||||
CloseHandle(hModuleSnap);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
do {
|
|
||||||
if(strstr( modent.szExePath, name)) {
|
|
||||||
if(strstr( modent.szExePath, "metamod"))
|
|
||||||
continue;
|
|
||||||
base_addr->addr = modent.modBaseAddr;
|
|
||||||
base_addr->len = modent.modBaseSize;
|
|
||||||
CloseHandle(hModuleSnap);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
} while(Module32Next(hModuleSnap, &modent));
|
|
||||||
CloseHandle(hModuleSnap);
|
|
||||||
#else
|
|
||||||
struct v_data vdata;
|
|
||||||
vdata.fname = name;
|
|
||||||
if(dl_iterate_phdr(callback, &vdata)){
|
|
||||||
base_addr->addr = vdata.baddr;
|
|
||||||
base_addr->len = vdata.blen;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
base_addr->addr = NULL;
|
|
||||||
base_addr->len = 0;
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
int find_base_from_list(const char *name[], struct base_addr_t *base_addr)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
int i = 0;
|
|
||||||
base_addr->addr = NULL;
|
|
||||||
base_addr->len = 0;
|
|
||||||
|
|
||||||
if (name == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
while (name[i] != NULL && !(ret = find_base(name[i], base_addr)))
|
|
||||||
i++;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
int write_signature(const void* addr, const void* signature)
|
|
||||||
{
|
|
||||||
if(!addr)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
unsigned int u_addr_sign;
|
|
||||||
unsigned int sign_len;
|
|
||||||
unsigned int sign_off;
|
|
||||||
unsigned int u_addr;
|
|
||||||
|
|
||||||
sign_len = ((unsigned char *)signature)[SIGN_LEN_BYTE];
|
|
||||||
sign_off = ((unsigned char *)signature)[SIGN_OFFSET_BYTE];
|
|
||||||
u_addr = (unsigned int)addr;
|
|
||||||
u_addr_sign = (unsigned int)signature;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
|
||||||
WriteProcessMemory(h_process, (void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len, NULL);
|
|
||||||
CloseHandle(h_process);
|
|
||||||
#else
|
|
||||||
lock_region(addr, sign_len, sign_off, 1);
|
|
||||||
memcpy((void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len);
|
|
||||||
lock_region(addr, sign_len, sign_off, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int read_signature(const void *addr, void *signature)
|
|
||||||
{
|
|
||||||
unsigned int u_addr_sign;
|
|
||||||
unsigned int sign_len;
|
|
||||||
unsigned int sign_off;
|
|
||||||
unsigned int u_addr;
|
|
||||||
|
|
||||||
sign_len = ((unsigned char *)signature)[SIGN_LEN_BYTE];
|
|
||||||
sign_off = ((unsigned char *)signature)[SIGN_OFFSET_BYTE];
|
|
||||||
u_addr = (unsigned int)addr;
|
|
||||||
u_addr_sign = (unsigned int)signature;
|
|
||||||
|
|
||||||
#ifdef WIN32
|
|
||||||
HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
|
|
||||||
ReadProcessMemory(h_process, (void *)(u_addr+sign_off), (void *)(u_addr_sign+SIGN_HEADER_LEN), sign_len, NULL);
|
|
||||||
CloseHandle(h_process);
|
|
||||||
#else
|
|
||||||
lock_region(addr, sign_len, sign_off, 1);
|
|
||||||
memcpy((void *)(u_addr_sign+SIGN_HEADER_LEN), (void *)(u_addr+sign_off), sign_len);
|
|
||||||
lock_region(addr, sign_len, sign_off, 0);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_original_signature(const void *offset, const void *new_sig, void *&org_sig)
|
|
||||||
{
|
|
||||||
unsigned int sign_len;
|
|
||||||
|
|
||||||
if(!offset)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
sign_len = ((unsigned char *)new_sig)[SIGN_LEN_BYTE];
|
|
||||||
org_sig = malloc(sign_len + SIGN_HEADER_LEN);
|
|
||||||
memcpy(org_sig, new_sig, SIGN_HEADER_LEN);
|
|
||||||
return read_signature(offset, org_sig);
|
|
||||||
}
|
|
||||||
|
|
16
signature.h
16
signature.h
@ -1,16 +0,0 @@
|
|||||||
#ifndef _INCLUDE_SIGNATURE_
|
|
||||||
#define _INCLUDE_SIGNATURE_
|
|
||||||
|
|
||||||
struct base_addr_t{
|
|
||||||
void *addr;
|
|
||||||
unsigned int len;
|
|
||||||
};
|
|
||||||
|
|
||||||
void *find_signature(const char *mask, struct base_addr_t *base_addr, int pure);
|
|
||||||
int find_base(const char *name, struct base_addr_t *base_addr);
|
|
||||||
int find_base_from_list(const char *name[], struct base_addr_t *base_addr);
|
|
||||||
int write_signature(const void *addr, const void *signature);
|
|
||||||
int read_signature(const void *addr, void *signature);
|
|
||||||
int get_original_signature(const void *offset, const void *new_sig, void *&org_sig);
|
|
||||||
|
|
||||||
#endif //_INCLUDE_SIGNATURE_
|
|
232
sm_symtable.h
Normal file
232
sm_symtable.h
Normal file
@ -0,0 +1,232 @@
|
|||||||
|
/**
|
||||||
|
* vim: set ts=4 sw=4 tw=99 noet :
|
||||||
|
* =============================================================================
|
||||||
|
* SourceMod
|
||||||
|
* Copyright (C) 2004-2009 AlliedModders LLC. All rights reserved.
|
||||||
|
* =============================================================================
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it under
|
||||||
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||||
|
* Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
* details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along with
|
||||||
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||||
|
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||||
|
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||||
|
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||||
|
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||||
|
* this exception to all derivative works. AlliedModders LLC defines further
|
||||||
|
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||||
|
* or <http://www.sourcemod.net/license.php>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||||
|
#define _INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
#define KESTRING_TABLE_START_SIZE 65536
|
||||||
|
|
||||||
|
struct Symbol
|
||||||
|
{
|
||||||
|
size_t length;
|
||||||
|
uint32_t hash;
|
||||||
|
void *address;
|
||||||
|
Symbol *tbl_next;
|
||||||
|
|
||||||
|
inline char *buffer()
|
||||||
|
{
|
||||||
|
return reinterpret_cast<char *>(this + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class SymbolTable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~SymbolTable()
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < nbuckets; i++)
|
||||||
|
{
|
||||||
|
Symbol *sym = buckets[i];
|
||||||
|
while (sym != NULL)
|
||||||
|
{
|
||||||
|
Symbol *next = sym->tbl_next;
|
||||||
|
free(sym);
|
||||||
|
sym = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Initialize()
|
||||||
|
{
|
||||||
|
buckets = (Symbol **)malloc(sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
|
||||||
|
if (buckets == NULL)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memset(buckets, 0, sizeof(Symbol *) * KESTRING_TABLE_START_SIZE);
|
||||||
|
|
||||||
|
nbuckets = KESTRING_TABLE_START_SIZE;
|
||||||
|
nused = 0;
|
||||||
|
bucketmask = KESTRING_TABLE_START_SIZE - 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint32_t HashString(const char *data, size_t len)
|
||||||
|
{
|
||||||
|
#undef get16bits
|
||||||
|
#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
|
||||||
|
|| defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
|
||||||
|
#define get16bits(d) (*((const uint16_t *) (d)))
|
||||||
|
#endif
|
||||||
|
#if !defined (get16bits)
|
||||||
|
#define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8)\
|
||||||
|
+(uint32_t)(((const uint8_t *)(d))[0]) )
|
||||||
|
#endif
|
||||||
|
uint32_t hash = len, tmp;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
if (len <= 0 || data == NULL)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rem = len & 3;
|
||||||
|
len >>= 2;
|
||||||
|
|
||||||
|
/* Main loop */
|
||||||
|
for (;len > 0; len--) {
|
||||||
|
hash += get16bits (data);
|
||||||
|
tmp = (get16bits (data+2) << 11) ^ hash;
|
||||||
|
hash = (hash << 16) ^ tmp;
|
||||||
|
data += 2 * sizeof (uint16_t);
|
||||||
|
hash += hash >> 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle end cases */
|
||||||
|
switch (rem) {
|
||||||
|
case 3: hash += get16bits (data);
|
||||||
|
hash ^= hash << 16;
|
||||||
|
hash ^= data[sizeof (uint16_t)] << 18;
|
||||||
|
hash += hash >> 11;
|
||||||
|
break;
|
||||||
|
case 2: hash += get16bits (data);
|
||||||
|
hash ^= hash << 11;
|
||||||
|
hash += hash >> 17;
|
||||||
|
break;
|
||||||
|
case 1: hash += *data;
|
||||||
|
hash ^= hash << 10;
|
||||||
|
hash += hash >> 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force "avalanching" of final 127 bits */
|
||||||
|
hash ^= hash << 3;
|
||||||
|
hash += hash >> 5;
|
||||||
|
hash ^= hash << 4;
|
||||||
|
hash += hash >> 17;
|
||||||
|
hash ^= hash << 25;
|
||||||
|
hash += hash >> 6;
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
|
||||||
|
#undef get16bits
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol **FindSymbolBucket(const char *str, size_t len, uint32_t hash)
|
||||||
|
{
|
||||||
|
uint32_t bucket = hash & bucketmask;
|
||||||
|
Symbol **pkvs = &buckets[bucket];
|
||||||
|
|
||||||
|
Symbol *kvs = *pkvs;
|
||||||
|
while (kvs != NULL)
|
||||||
|
{
|
||||||
|
if (len == kvs->length && memcmp(str, kvs->buffer(), len * sizeof(char)) == 0)
|
||||||
|
{
|
||||||
|
return pkvs;
|
||||||
|
}
|
||||||
|
pkvs = &kvs->tbl_next;
|
||||||
|
kvs = *pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResizeSymbolTable()
|
||||||
|
{
|
||||||
|
uint32_t xnbuckets = nbuckets * 2;
|
||||||
|
Symbol **xbuckets = (Symbol **)malloc(sizeof(Symbol *) * xnbuckets);
|
||||||
|
if (xbuckets == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(xbuckets, 0, sizeof(Symbol *) * xnbuckets);
|
||||||
|
uint32_t xbucketmask = xnbuckets - 1;
|
||||||
|
for (uint32_t i = 0; i < nbuckets; i++)
|
||||||
|
{
|
||||||
|
Symbol *sym = buckets[i];
|
||||||
|
while (sym != NULL)
|
||||||
|
{
|
||||||
|
Symbol *next = sym->tbl_next;
|
||||||
|
uint32_t bucket = sym->hash & xbucketmask;
|
||||||
|
sym->tbl_next = xbuckets[bucket];
|
||||||
|
xbuckets[bucket] = sym;
|
||||||
|
sym = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buckets);
|
||||||
|
buckets = xbuckets;
|
||||||
|
nbuckets = xnbuckets;
|
||||||
|
bucketmask = xbucketmask;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *FindSymbol(const char *str, size_t len)
|
||||||
|
{
|
||||||
|
uint32_t hash = HashString(str, len);
|
||||||
|
Symbol **pkvs = FindSymbolBucket(str, len, hash);
|
||||||
|
return *pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *InternSymbol(const char* str, size_t len, void *address)
|
||||||
|
{
|
||||||
|
uint32_t hash = HashString(str, len);
|
||||||
|
Symbol **pkvs = FindSymbolBucket(str, len, hash);
|
||||||
|
if (*pkvs != NULL)
|
||||||
|
{
|
||||||
|
return *pkvs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Symbol *kvs = (Symbol *)malloc(sizeof(Symbol) + sizeof(char) * (len + 1));
|
||||||
|
kvs->length = len;
|
||||||
|
kvs->hash = hash;
|
||||||
|
kvs->address = address;
|
||||||
|
kvs->tbl_next = NULL;
|
||||||
|
memcpy(kvs + 1, str, sizeof(char) * (len + 1));
|
||||||
|
*pkvs = kvs;
|
||||||
|
nused++;
|
||||||
|
|
||||||
|
if (nused > nbuckets && nbuckets <= INT_MAX / 2)
|
||||||
|
{
|
||||||
|
ResizeSymbolTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
return kvs;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
uint32_t nbuckets;
|
||||||
|
uint32_t nused;
|
||||||
|
uint32_t bucketmask;
|
||||||
|
Symbol **buckets;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //_INCLUDE_SOURCEMOD_CORE_SYMBOLTABLE_H_
|
Loading…
Reference in New Issue
Block a user