diff --git a/.gitmodules b/.gitmodules index ca605caa12..dce1debb8a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,3 +9,6 @@ [submodule "hl2sdk-manifests"] path = hl2sdk-manifests url = https://github.com/alliedmodders/hl2sdk-manifests.git +[submodule "public/safetyhook"] + path = public/safetyhook + url = https://github.com/alliedmodders/safetyhook diff --git a/AMBuildScript b/AMBuildScript index 50af518b5a..883c33a943 100644 --- a/AMBuildScript +++ b/AMBuildScript @@ -55,6 +55,7 @@ class SMConfig(object): self.target_archs = set() self.enable_asan = getattr(builder.options, 'enable_asan', False) self.asan_libs = {} + self.libsafetyhook = {} if builder.options.targets: target_archs = builder.options.targets.split(',') @@ -520,6 +521,17 @@ class SMConfig(object): return binary + def AddCDetour(self, binary): + public_path = os.path.join(builder.sourcePath, 'public') + binary.sources += [ os.path.join(public_path, 'CDetour', 'detours.cpp') ] + binary.compiler.cxxincludes += [ os.path.join(public_path, 'safetyhook', 'include') ] + + for task in self.libsafetyhook: + if task.target.arch == binary.compiler.target.arch: + binary.compiler.linkflags += [task.binary] + return + raise Exception('No suitable build of safetyhook was found.') + def HL2Library(self, context, compiler, name, sdk): binary = self.Library(context, compiler, name) self.ConfigureForExtension(context, binary.compiler) @@ -568,6 +580,16 @@ if SM.use_auto_versioning(): { 'SM': SM } ) +class SafetyHookShim(object): + def __init__(self): + self.all_targets = {} + self.libsafetyhook = {} + +SafetyHook = SafetyHookShim() +SafetyHook.all_targets = SM.all_targets +builder.Build('public/safetyhook/AMBuilder', {'SafetyHook': SafetyHook }) +SM.libsafetyhook = SafetyHook.libsafetyhook + class SPRoot(object): def __init__(self): self.generated_headers = SM.generated_headers diff --git a/core/HalfLife2.cpp b/core/HalfLife2.cpp index 7600917b40..f0e1013f75 100644 --- a/core/HalfLife2.cpp +++ b/core/HalfLife2.cpp @@ -413,6 +413,17 @@ ServerClass *CHalfLife2::FindServerClass(const char *classname) return pInfo->sc; } +ServerClass *CHalfLife2::FindEntityServerClass(CBaseEntity *pEntity) +{ + IServerNetworkable* pNetwork = ((IServerUnknown *)pEntity)->GetNetworkable(); + if (pNetwork == nullptr) + { + return nullptr; + } + + return pNetwork->GetServerClass(); +} + DataTableInfo *CHalfLife2::_FindServerClass(const char *classname) { DataTableInfo *pInfo = NULL; diff --git a/core/HalfLife2.h b/core/HalfLife2.h index b3f9b534ef..8497704a30 100644 --- a/core/HalfLife2.h +++ b/core/HalfLife2.h @@ -221,6 +221,7 @@ class CHalfLife2 : bool FindSendPropInfo(const char *classname, const char *offset, sm_sendprop_info_t *info); datamap_t *GetDataMap(CBaseEntity *pEntity); ServerClass *FindServerClass(const char *classname); + ServerClass *FindEntityServerClass(CBaseEntity *pEntity); typedescription_t *FindInDataMap(datamap_t *pMap, const char *offset); bool FindDataMapInfo(datamap_t *pMap, const char *offset, sm_datatable_info_t *pDataTable); void SetEdictStateChanged(edict_t *pEdict, unsigned short offset); diff --git a/core/logic/ExtensionSys.cpp b/core/logic/ExtensionSys.cpp index 867b2898ea..4406a7943a 100644 --- a/core/logic/ExtensionSys.cpp +++ b/core/logic/ExtensionSys.cpp @@ -395,11 +395,6 @@ void CExtension::AddDependency(const IfaceInfo *pInfo) } } -bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2) -{ - return (i1.iface == i2.iface) && (i1.owner == i2.owner); -} - void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface) { IfaceInfo info; diff --git a/core/logic/ShareSys.h b/core/logic/ShareSys.h index 20fc957967..408a23eb45 100644 --- a/core/logic/ShareSys.h +++ b/core/logic/ShareSys.h @@ -59,7 +59,7 @@ namespace SourceMod struct IfaceInfo { - bool operator ==(const IfaceInfo &info) + bool operator ==(const IfaceInfo &info) const { return (info.iface == iface && info.owner == owner); } diff --git a/core/logic/TextParsers.cpp b/core/logic/TextParsers.cpp index 318cc4f0dc..8ac9db95d6 100644 --- a/core/logic/TextParsers.cpp +++ b/core/logic/TextParsers.cpp @@ -342,6 +342,7 @@ SMCError TextParsers::ParseStream_SMC(void *stream, SMCResult res; SMCStates states; char c; + bool end_of_last_buffer_was_backslash = false; StringInfo strings[3]; StringInfo emptystring; @@ -383,6 +384,10 @@ SMCError TextParsers::ParseStream_SMC(void *stream, if (reparse_point) { read += (parse_point - reparse_point); + if(read > 0) + { + end_of_last_buffer_was_backslash = reparse_point[-1] == '\\'; + } parse_point = reparse_point; reparse_point = NULL; } @@ -454,7 +459,7 @@ SMCError TextParsers::ParseStream_SMC(void *stream, if (in_quote) { /* If i was 0, we could have reparsed, so make sure there's no buffer underrun */ - if ((&parse_point[i] != in_buf) && c == '"' && parse_point[i-1] != '\\') + if ( (&parse_point[i] != in_buf) && c == '"' && !((i == 0 && end_of_last_buffer_was_backslash) || (i > 0 && parse_point[i-1] == '\\')) ) { /* If we reached a quote in an ignore phase, * we're staging a string and we must rotate it out. @@ -726,6 +731,7 @@ SMCError TextParsers::ParseStream_SMC(void *stream, if (parse_point) { parse_point = &parse_point[read]; + end_of_last_buffer_was_backslash = parse_point[-1] == '\\'; parse_point -= bytes; } } diff --git a/core/logic/smn_filesystem.cpp b/core/logic/smn_filesystem.cpp index 0577bf4d59..4ca57e62ce 100644 --- a/core/logic/smn_filesystem.cpp +++ b/core/logic/smn_filesystem.cpp @@ -317,6 +317,10 @@ class FileNatives : } virtual bool LogPrint(const char *msg) { + if (!g_pLogHook) { + return false; + } + cell_t result = 0; g_pLogHook->PushString(msg); g_pLogHook->Execute(&result); @@ -751,6 +755,39 @@ static cell_t sm_SetFilePermissions(IPluginContext *pContext, const cell_t *para #endif } +static cell_t sm_GetFilePermissions(IPluginContext *pContext, const cell_t *params) +{ + char *name; + char realpath[PLATFORM_MAX_PATH]; + + pContext->LocalToString(params[1], &name); + g_pSM->BuildPath(Path_Game, realpath, sizeof(realpath), "%s", name); + + cell_t *mask; + pContext->LocalToPhysAddr(params[2], &mask); + +#if defined PLATFORM_WINDOWS + struct _stat buffer; + cell_t valid = _stat(realpath, &buffer) == 0; + + if ((buffer.st_mode & _S_IREAD) != 0) { + *mask |= (FPERM_U_READ|FPERM_G_READ|FPERM_O_READ)|(FPERM_U_EXEC|FPERM_G_EXEC|FPERM_O_EXEC); + } + + if ((buffer.st_mode & _S_IWRITE) != 0) { + *mask |= (FPERM_U_WRITE|FPERM_G_WRITE|FPERM_O_WRITE); + } + + return valid; +#else + struct stat buffer; + cell_t valid = stat(realpath, &buffer) == 0; + + *mask = buffer.st_mode; + return valid; +#endif +} + static cell_t sm_CreateDirectory(IPluginContext *pContext, const cell_t *params) { char *name; @@ -1224,6 +1261,7 @@ REGISTER_NATIVES(filesystem) {"RemoveGameLogHook", sm_RemoveGameLogHook}, {"CreateDirectory", sm_CreateDirectory}, {"SetFilePermissions", sm_SetFilePermissions}, + {"GetFilePermissions", sm_GetFilePermissions}, {"File.ReadLine", sm_ReadFileLine}, {"File.Read", sm_ReadFile}, diff --git a/core/smn_entities.cpp b/core/smn_entities.cpp index d2986ca437..929b4a4a8f 100644 --- a/core/smn_entities.cpp +++ b/core/smn_entities.cpp @@ -134,12 +134,10 @@ inline edict_t *BaseEntityToEdict(CBaseEntity *pEntity) { IServerUnknown *pUnk = (IServerUnknown *)pEntity; IServerNetworkable *pNet = pUnk->GetNetworkable(); - - if (!pNet) + if (pNet == nullptr) { - return NULL; + return nullptr; } - return pNet->GetEdict(); } @@ -363,14 +361,20 @@ static cell_t IsValidEntity(IPluginContext *pContext, const cell_t *params) static cell_t IsEntNetworkable(IPluginContext *pContext, const cell_t *params) { - edict_t *pEdict = GetEdict(params[1]); + IServerUnknown *pUnknown = (IServerUnknown *)g_HL2.ReferenceToEntity(params[1]); + if (!pUnknown) + { + return 0; + } - if (!pEdict) + IServerNetworkable *pNet = pUnknown->GetNetworkable(); + if (!pNet) { return 0; } - return (pEdict->GetNetworkable() != NULL) ? 1 : 0; + edict_t* edict = pNet->GetEdict(); + return (edict && !edict->IsFree()) ? 1 : 0; } static cell_t GetEntityCount(IPluginContext *pContext, const cell_t *params) @@ -436,14 +440,12 @@ static cell_t GetEntityNetClass(IPluginContext *pContext, const cell_t *params) return pContext->ThrowNativeError("Invalid entity (%d - %d)", g_HL2.ReferenceToIndex(params[1]), params[1]); } - IServerNetworkable *pNet = pUnk->GetNetworkable(); - if (!pNet) + ServerClass *pClass = g_HL2.FindEntityServerClass(pEntity); + if (!pClass) { return 0; } - ServerClass *pClass = pNet->GetServerClass(); - pContext->StringToLocal(params[2], params[3], pClass->GetName()); return 1; @@ -1270,13 +1272,11 @@ static cell_t SetEntDataString(IPluginContext *pContext, const cell_t *params) #define FIND_PROP_SEND(type, type_name) \ sm_sendprop_info_t info;\ SendProp *pProp; \ - IServerUnknown *pUnk = (IServerUnknown *)pEntity; \ - IServerNetworkable *pNet = pUnk->GetNetworkable(); \ - if (!pNet) \ - { \ - return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); \ + ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity); \ + if (pServerClass == nullptr) { \ + pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]); \ } \ - if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) \ + if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info)) \ { \ const char *class_name = g_HL2.GetEntityClassname(pEntity); \ return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", \ @@ -1434,13 +1434,13 @@ static cell_t GetEntPropArraySize(IPluginContext *pContext, const cell_t *params { sm_sendprop_info_t info; - IServerUnknown *pUnk = (IServerUnknown *)pEntity; - IServerNetworkable *pNet = pUnk->GetNetworkable(); - if (!pNet) + ServerClass *pServerClass = g_HL2.FindEntityServerClass(pEntity); + if (pServerClass == nullptr) { - return pContext->ThrowNativeError("Edict %d (%d) is not networkable", g_HL2.ReferenceToIndex(params[1]), params[1]); + return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", g_HL2.ReferenceToIndex(params[1]), params[1]); } - if (!g_HL2.FindSendPropInfo(pNet->GetServerClass()->GetName(), prop, &info)) + + if (!g_HL2.FindSendPropInfo(pServerClass->GetName(), prop, &info)) { const char *class_name = g_HL2.GetEntityClassname(pEntity); return pContext->ThrowNativeError("Property \"%s\" not found (entity %d/%s)", @@ -2079,13 +2079,7 @@ static cell_t SetEntPropEnt(IPluginContext *pContext, const cell_t *params) edict_t *pOtherEdict = NULL; if (pOther) { - IServerNetworkable *pNetworkable = ((IServerUnknown *) pOther)->GetNetworkable(); - if (!pNetworkable) - { - return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]); - } - - pOtherEdict = pNetworkable->GetEdict(); + pOtherEdict = BaseEntityToEdict(pOther); if (!pOtherEdict || pOtherEdict->IsFree()) { return pContext->ThrowNativeError("Entity %d (%d) does not have a valid edict", g_HL2.ReferenceToIndex(params[4]), params[4]); diff --git a/extensions/cstrike/AMBuilder b/extensions/cstrike/AMBuilder index d1f65409b7..97a8209651 100644 --- a/extensions/cstrike/AMBuilder +++ b/extensions/cstrike/AMBuilder @@ -9,15 +9,7 @@ project.sources += [ 'timeleft.cpp', 'forwards.cpp', 'util_cstrike.cpp', - '../../public/smsdk_ext.cpp', - '../../public/CDetour/detours.cpp', - '../../public/asm/asm.c', - '../../public/libudis86/decode.c', - '../../public/libudis86/itab.c', - '../../public/libudis86/syn-att.c', - '../../public/libudis86/syn-intel.c', - '../../public/libudis86/syn.c', - '../../public/libudis86/udis86.c', + '../../public/smsdk_ext.cpp' ] for sdk_name in ['css', 'csgo']: @@ -34,6 +26,8 @@ for sdk_name in ['css', 'csgo']: cxx.defines += ['HAVE_STRING_H'] binary = SM.HL2ExtConfig(project, builder, cxx, 'game.cstrike.ext.' + sdk['extension'], sdk) + SM.AddCDetour(binary) + if sdk_name == 'csgo': compiler = binary.compiler compiler.cxxincludes += [os.path.join(sdk['path'], 'public', 'steam')] diff --git a/extensions/cstrike/natives.cpp b/extensions/cstrike/natives.cpp index a3fedb963e..aa6dd928fe 100644 --- a/extensions/cstrike/natives.cpp +++ b/extensions/cstrike/natives.cpp @@ -254,10 +254,13 @@ static cell_t CS_DropWeapon(IPluginContext *pContext, const cell_t *params) //Psychonic is awesome for this sm_sendprop_info_t spi; - IServerUnknown *pUnk = (IServerUnknown *)pWeapon; - IServerNetworkable *pNet = pUnk->GetNetworkable(); + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pWeapon); + if (pServerClass == nullptr) + { + return pContext->ThrowNativeError("Failed to retrieve entity %d server class!", params[2]); + } - if (!UTIL_FindDataTable(pNet->GetServerClass()->m_pTable, "DT_WeaponCSBase", &spi, 0)) + if (!UTIL_FindDataTable(pServerClass->m_pTable, "DT_WeaponCSBase", &spi, 0)) return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]); if (!gamehelpers->FindSendPropInfo("CBaseCombatWeapon", "m_hOwnerEntity", &spi)) diff --git a/extensions/dhooks/AMBuilder b/extensions/dhooks/AMBuilder index 151b922560..8c09573755 100644 --- a/extensions/dhooks/AMBuilder +++ b/extensions/dhooks/AMBuilder @@ -4,8 +4,11 @@ import os for cxx in builder.targets: binary = SM.ExtLibrary(builder, cxx, 'dhooks.ext') - # Only x86 on Linux and Windows is supported. - if binary.compiler.target.platform == 'mac' or binary.compiler.target.arch != 'x86': + # mac isn't supported + if binary.compiler.target.platform == 'mac': + continue + # Presently only x86_64 on Windows is supported + if binary.compiler.target.arch == 'x86_64' and binary.compiler.target.platform != 'windows': continue binary.compiler.defines += [ @@ -19,14 +22,17 @@ for cxx in builder.targets: binary.compiler.cxxincludes += [ os.path.join(SM.mms_root, 'core'), os.path.join(SM.mms_root, 'core', 'sourcehook'), + os.path.join(builder.sourcePath, 'extensions', 'dhooks'), os.path.join(builder.sourcePath, 'public', 'jit'), - os.path.join(builder.sourcePath, 'public', 'jit', 'x86'), os.path.join(builder.sourcePath, 'sourcepawn', 'include'), os.path.join(builder.sourcePath, 'sourcepawn', 'vm'), - os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86'), os.path.join(builder.sourcePath, 'extensions', 'dhooks', 'DynamicHooks'), ] + binary.compiler.includes += [ + os.path.join(builder.sourcePath, 'extensions', 'dhooks') + ] + binary.sources += [ 'extension.cpp', 'listeners.cpp', @@ -36,29 +42,41 @@ for cxx in builder.targets: 'util.cpp', 'dynhooks_sourcepawn.cpp', '../../public/smsdk_ext.cpp', - '../../public/asm/asm.c', - '../../public/libudis86/decode.c', - '../../public/libudis86/itab.c', - '../../public/libudis86/syn-att.c', - '../../public/libudis86/syn-intel.c', - '../../public/libudis86/syn.c', - '../../public/libudis86/udis86.c', - '../../sourcepawn/vm/x86/assembler-x86.cpp', + 'asm/asm.c', + 'libudis86/decode.c', + 'libudis86/itab.c', + 'libudis86/syn-att.c', + 'libudis86/syn-intel.c', + 'libudis86/syn.c', + 'libudis86/udis86.c', + # Dynamic Hooks + os.path.join('DynamicHooks', 'registers.cpp') ] - # DynamicHooks - binary.sources += [ - os.path.join('DynamicHooks', 'hook.cpp'), - os.path.join('DynamicHooks', 'manager.cpp'), - os.path.join('DynamicHooks', 'registers.cpp'), - os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), - os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), - os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'), - ] + if binary.compiler.target.arch == 'x86': + binary.sources += ['../../sourcepawn/vm/x86/assembler-x86.cpp'] + binary.compiler.cxxincludes += [ + os.path.join(builder.sourcePath, 'public', 'jit', 'x86'), + os.path.join(builder.sourcePath, 'sourcepawn', 'vm', 'x86') + ] + # DynamicHooks + binary.sources += [ + os.path.join('DynamicHooks', 'hook.cpp'), + os.path.join('DynamicHooks', 'manager.cpp'), + os.path.join('DynamicHooks', 'conventions', 'x86MsCdecl.cpp'), + os.path.join('DynamicHooks', 'conventions', 'x86MsStdcall.cpp'), + os.path.join('DynamicHooks', 'conventions', 'x86MsFastcall.cpp'), + ] + + if binary.compiler.target.platform == 'windows': + binary.sources += [os.path.join('DynamicHooks', 'conventions', 'x86MsThiscall.cpp')] + else: + binary.sources += [os.path.join('DynamicHooks', 'conventions', 'x86GccThiscall.cpp')] + + # Dynamic detour is only supported on x86 + binary.compiler.defines += ['DHOOKS_DYNAMIC_DETOUR'] - if binary.compiler.target.platform == 'windows': - binary.sources += [os.path.join('DynamicHooks', 'conventions', 'x86MsThiscall.cpp')] - else: - binary.sources += [os.path.join('DynamicHooks', 'conventions', 'x86GccThiscall.cpp')] + elif binary.compiler.target.arch == 'x86_64': + binary.compiler.defines += ['PLATFORM_X64'] SM.extensions += [builder.Add(binary)] diff --git a/extensions/dhooks/DynamicHooks/convention.h b/extensions/dhooks/DynamicHooks/convention.h index ae4d613884..e9a63ed479 100644 --- a/extensions/dhooks/DynamicHooks/convention.h +++ b/extensions/dhooks/DynamicHooks/convention.h @@ -111,7 +111,7 @@ The data type you would like to get the size of. @param : The alignment that should be used. */ -inline int GetDataTypeSize(DataTypeSized_t type, int iAlignment=4) +inline size_t GetDataTypeSize(DataTypeSized_t type, int iAlignment=4) { switch(type.type) { @@ -257,9 +257,9 @@ class ICallingConvention int size = GetArgStackSize() + GetArgRegisterSize(); std::unique_ptr pSavedCallArguments = std::make_unique(size); size_t offset = 0; - for (size_t i = 0; i < m_vecArgTypes.size(); i++) { + for (unsigned int i = 0; i < m_vecArgTypes.size(); i++) { DataTypeSized_t &type = m_vecArgTypes[i]; - memcpy((void *)((unsigned long)pSavedCallArguments.get() + offset), GetArgumentPtr(i, pRegisters), type.size); + memcpy((void *)((uintptr_t)pSavedCallArguments.get() + offset), GetArgumentPtr(i, pRegisters), type.size); offset += type.size; } m_pSavedCallArguments.push_back(std::move(pSavedCallArguments)); @@ -271,7 +271,7 @@ class ICallingConvention size_t offset = 0; for (size_t i = 0; i < m_vecArgTypes.size(); i++) { DataTypeSized_t &type = m_vecArgTypes[i]; - memcpy(GetArgumentPtr(i, pRegisters), (void *)((unsigned long)pSavedCallArguments + offset), type.size); + memcpy(GetArgumentPtr((unsigned int)i, pRegisters), (void *)((uintptr_t)pSavedCallArguments + offset), type.size); offset += type.size; } m_pSavedCallArguments.pop_back(); diff --git a/extensions/dhooks/DynamicHooks/registers.cpp b/extensions/dhooks/DynamicHooks/registers.cpp index f2200630c3..25c45b5821 100644 --- a/extensions/dhooks/DynamicHooks/registers.cpp +++ b/extensions/dhooks/DynamicHooks/registers.cpp @@ -116,7 +116,7 @@ CRegisters::CRegisters(std::vector registers) // >> 64-bit General purpose registers // ======================================================================== // 64-bit mode only - /* +#ifdef PLATFORM_X64 m_rax = CreateRegister(registers, RAX, 8); m_rcx = CreateRegister(registers, RCX, 8); m_rdx = CreateRegister(registers, RDX, 8); @@ -125,10 +125,7 @@ CRegisters::CRegisters(std::vector registers) m_rbp = CreateRegister(registers, RBP, 8); m_rsi = CreateRegister(registers, RSI, 8); m_rdi = CreateRegister(registers, RDI, 8); - */ - - // 64-bit mode only - /* + m_r8 = CreateRegister(registers, R8, 8); m_r9 = CreateRegister(registers, R9, 8); m_r10 = CreateRegister(registers, R10, 8); @@ -137,7 +134,7 @@ CRegisters::CRegisters(std::vector registers) m_r13 = CreateRegister(registers, R13, 8); m_r14 = CreateRegister(registers, R14, 8); m_r15 = CreateRegister(registers, R15, 8); - */ +#endif // ======================================================================== // >> 64-bit MM (MMX) registers @@ -165,7 +162,7 @@ CRegisters::CRegisters(std::vector registers) m_xmm7 = CreateRegister(registers, XMM7, 16, 16); // 64-bit mode only - /* +#ifdef PLATFORM_X64 m_xmm8 = CreateRegister(registers, XMM8, 16); m_xmm9 = CreateRegister(registers, XMM9, 16); m_xmm10 = CreateRegister(registers, XMM10, 16); @@ -174,7 +171,7 @@ CRegisters::CRegisters(std::vector registers) m_xmm13 = CreateRegister(registers, XMM13, 16); m_xmm14 = CreateRegister(registers, XMM14, 16); m_xmm15 = CreateRegister(registers, XMM15, 16); - */ +#endif // ======================================================================== // >> 16-bit Segment registers @@ -282,7 +279,7 @@ CRegisters::~CRegisters() // >> 64-bit General purpose registers // ======================================================================== // 64-bit mode only - /* +#ifdef PLATFORM_X64 DeleteRegister(m_rax); DeleteRegister(m_rcx); DeleteRegister(m_rdx); @@ -291,10 +288,8 @@ CRegisters::~CRegisters() DeleteRegister(m_rbp); DeleteRegister(m_rsi); DeleteRegister(m_rdi); - */ // 64-bit mode only - /* DeleteRegister(m_r8); DeleteRegister(m_r9); DeleteRegister(m_r10); @@ -303,7 +298,7 @@ CRegisters::~CRegisters() DeleteRegister(m_r13); DeleteRegister(m_r14); DeleteRegister(m_r15); - */ +#endif // ======================================================================== // >> 64-bit MM (MMX) registers @@ -330,7 +325,7 @@ CRegisters::~CRegisters() DeleteRegister(m_xmm7); // 64-bit mode only - /* +#ifdef PLATFORM_X64 DeleteRegister(m_xmm8); DeleteRegister(m_xmm9); DeleteRegister(m_xmm10); @@ -339,7 +334,7 @@ CRegisters::~CRegisters() DeleteRegister(m_xmm13); DeleteRegister(m_xmm14); DeleteRegister(m_xmm15); - */ +#endif // ======================================================================== // >> 2-bit Segment registers diff --git a/extensions/dhooks/DynamicHooks/registers.h b/extensions/dhooks/DynamicHooks/registers.h index 854c40f98b..e65ee36193 100644 --- a/extensions/dhooks/DynamicHooks/registers.h +++ b/extensions/dhooks/DynamicHooks/registers.h @@ -132,8 +132,7 @@ enum Register_t // ======================================================================== // >> 64-bit General purpose registers // ======================================================================== - // 64-bit mode only - /* +#ifdef PLATFORM_X64 RAX, RCX, RDX, @@ -142,10 +141,7 @@ enum Register_t RBP, RSI, RDI, - */ - // 64-bit mode only - /* R8, R9, R10, @@ -154,7 +150,7 @@ enum Register_t R13, R14, R15, - */ +#endif // ======================================================================== // >> 64-bit MM (MMX) registers @@ -181,7 +177,7 @@ enum Register_t XMM7, // 64-bit mode only - /* +#ifdef PLATFORM_X64 XMM8, XMM9, XMM10, @@ -190,7 +186,7 @@ enum Register_t XMM13, XMM14, XMM15, - */ +#endif // ======================================================================== // >> 16-bit Segment registers @@ -377,7 +373,7 @@ class CRegisters // >> 64-bit General purpose registers // ======================================================================== // 64-bit mode only - /* +#ifdef PLATFORM_X64 CRegister* m_rax; CRegister* m_rcx; CRegister* m_rdx; @@ -386,10 +382,7 @@ class CRegisters CRegister* m_rbp; CRegister* m_rsi; CRegister* m_rdi; - */ - // 64-bit mode only - /* CRegister* m_r8; CRegister* m_r9; CRegister* m_r10; @@ -398,7 +391,7 @@ class CRegisters CRegister* m_r13; CRegister* m_r14; CRegister* m_r15; - */ +#endif // ======================================================================== // >> 64-bit MM (MMX) registers @@ -425,7 +418,7 @@ class CRegisters CRegister* m_xmm7; // 64-bit mode only - /* +#ifdef PLATFORM_X64 CRegister* m_xmm8; CRegister* m_xmm9; CRegister* m_xmm10; @@ -434,7 +427,7 @@ class CRegisters CRegister* m_xmm13; CRegister* m_xmm14; CRegister* m_xmm15; - */ +#endif // ======================================================================== // >> 16-bit Segment registers diff --git a/public/asm/asm.c b/extensions/dhooks/asm/asm.c similarity index 100% rename from public/asm/asm.c rename to extensions/dhooks/asm/asm.c diff --git a/public/asm/asm.h b/extensions/dhooks/asm/asm.h similarity index 100% rename from public/asm/asm.h rename to extensions/dhooks/asm/asm.h diff --git a/extensions/dhooks/dynhooks_sourcepawn.cpp b/extensions/dhooks/dynhooks_sourcepawn.cpp index 8b148fe7d8..2149a00c73 100644 --- a/extensions/dhooks/dynhooks_sourcepawn.cpp +++ b/extensions/dhooks/dynhooks_sourcepawn.cpp @@ -63,15 +63,18 @@ DetourMap g_pPostDetours; void UnhookFunction(HookType_t hookType, CHook *pDetour) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) CHookManager *pDetourManager = GetHookManager(); pDetour->RemoveCallback(hookType, (HookHandlerFn *)(void *)&HandleDetour); // Only disable the detour if there are no more listeners. if (!pDetour->AreCallbacksRegistered()) pDetourManager->UnhookFunction(pDetour->m_pFunc); +#endif } bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) DetourMap *map; if (hookType == HOOKTYPE_PRE) map = &g_pPreDetours; @@ -102,10 +105,14 @@ bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, wrappers->push_back(pWrapper); return true; +#else + return false; +#endif } bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction *pCallback) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) DetourMap *map; if (hookType == HOOKTYPE_PRE) map = &g_pPreDetours; @@ -139,10 +146,14 @@ bool RemoveDetourPluginHook(HookType_t hookType, CHook *pDetour, IPluginFunction } return bRemoved; +#else + return false; +#endif } void RemoveAllCallbacksForContext(HookType_t hookType, DetourMap *map, IPluginContext *pContext) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) PluginCallbackList *wrappers; CDynamicHooksSourcePawn *pWrapper; DetourMap::iterator it = map->iter(); @@ -170,16 +181,20 @@ void RemoveAllCallbacksForContext(HookType_t hookType, DetourMap *map, IPluginCo it.erase(); } } +#endif } void RemoveAllCallbacksForContext(IPluginContext *pContext) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) RemoveAllCallbacksForContext(HOOKTYPE_PRE, &g_pPreDetours, pContext); RemoveAllCallbacksForContext(HOOKTYPE_POST, &g_pPostDetours, pContext); +#endif } void CleanupDetours(HookType_t hookType, DetourMap *map) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) PluginCallbackList *wrappers; CDynamicHooksSourcePawn *pWrapper; DetourMap::iterator it = map->iter(); @@ -199,14 +214,18 @@ void CleanupDetours(HookType_t hookType, DetourMap *map) UnhookFunction(hookType, it->key); } map->clear(); +#endif } void CleanupDetours() { +#if defined( DHOOKS_DYNAMIC_DETOUR ) CleanupDetours(HOOKTYPE_PRE, &g_pPreDetours); CleanupDetours(HOOKTYPE_POST, &g_pPostDetours); +#endif } +#if defined( DHOOKS_DYNAMIC_DETOUR ) ICallingConvention *ConstructCallingConvention(HookSetup *setup) { // Convert function parameter types into DynamicHooks structures. @@ -249,6 +268,7 @@ ICallingConvention *ConstructCallingConvention(HookSetup *setup) return pCallConv; } +#endif // Some arguments might be optimized to be passed in registers instead of the stack. bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup) diff --git a/extensions/dhooks/dynhooks_sourcepawn.h b/extensions/dhooks/dynhooks_sourcepawn.h index 43428a4d33..2f04204860 100644 --- a/extensions/dhooks/dynhooks_sourcepawn.h +++ b/extensions/dhooks/dynhooks_sourcepawn.h @@ -62,7 +62,9 @@ class CDynamicHooksSourcePawn : public DHooksInfo { CallingConvention callConv; }; +#if defined( DHOOKS_DYNAMIC_DETOUR ) ICallingConvention *ConstructCallingConvention(HookSetup *setup); +#endif bool UpdateRegisterArgumentSizes(CHook* pDetour, HookSetup *setup); ReturnAction_t HandleDetour(HookType_t hookType, CHook* pDetour); bool AddDetourPluginHook(HookType_t hookType, CHook *pDetour, HookSetup *setup, IPluginFunction *pCallback); diff --git a/public/libudis86/decode.c b/extensions/dhooks/libudis86/decode.c similarity index 100% rename from public/libudis86/decode.c rename to extensions/dhooks/libudis86/decode.c diff --git a/public/libudis86/decode.h b/extensions/dhooks/libudis86/decode.h similarity index 100% rename from public/libudis86/decode.h rename to extensions/dhooks/libudis86/decode.h diff --git a/public/libudis86/extern.h b/extensions/dhooks/libudis86/extern.h similarity index 100% rename from public/libudis86/extern.h rename to extensions/dhooks/libudis86/extern.h diff --git a/public/libudis86/itab.c b/extensions/dhooks/libudis86/itab.c similarity index 100% rename from public/libudis86/itab.c rename to extensions/dhooks/libudis86/itab.c diff --git a/public/libudis86/itab.h b/extensions/dhooks/libudis86/itab.h similarity index 100% rename from public/libudis86/itab.h rename to extensions/dhooks/libudis86/itab.h diff --git a/public/libudis86/syn-att.c b/extensions/dhooks/libudis86/syn-att.c similarity index 100% rename from public/libudis86/syn-att.c rename to extensions/dhooks/libudis86/syn-att.c diff --git a/public/libudis86/syn-intel.c b/extensions/dhooks/libudis86/syn-intel.c similarity index 100% rename from public/libudis86/syn-intel.c rename to extensions/dhooks/libudis86/syn-intel.c diff --git a/public/libudis86/syn.c b/extensions/dhooks/libudis86/syn.c similarity index 100% rename from public/libudis86/syn.c rename to extensions/dhooks/libudis86/syn.c diff --git a/public/libudis86/syn.h b/extensions/dhooks/libudis86/syn.h similarity index 100% rename from public/libudis86/syn.h rename to extensions/dhooks/libudis86/syn.h diff --git a/public/libudis86/types.h b/extensions/dhooks/libudis86/types.h similarity index 100% rename from public/libudis86/types.h rename to extensions/dhooks/libudis86/types.h diff --git a/public/libudis86/udint.h b/extensions/dhooks/libudis86/udint.h similarity index 100% rename from public/libudis86/udint.h rename to extensions/dhooks/libudis86/udint.h diff --git a/public/libudis86/udis86.c b/extensions/dhooks/libudis86/udis86.c similarity index 100% rename from public/libudis86/udis86.c rename to extensions/dhooks/libudis86/udis86.c diff --git a/public/libudis86/udis86.h b/extensions/dhooks/libudis86/udis86.h similarity index 100% rename from public/libudis86/udis86.h rename to extensions/dhooks/libudis86/udis86.h diff --git a/extensions/dhooks/natives.cpp b/extensions/dhooks/natives.cpp index 8757e8319d..f228fcf306 100644 --- a/extensions/dhooks/natives.cpp +++ b/extensions/dhooks/natives.cpp @@ -338,6 +338,7 @@ cell_t Native_AddParam(IPluginContext *pContext, const cell_t *params) // native bool:DHookEnableDetour(Handle:setup, bool:post, DHookCallback:callback); cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) HookSetup *setup; if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) @@ -377,11 +378,15 @@ cell_t Native_EnableDetour(IPluginContext *pContext, const cell_t *params) // Add the plugin callback to the map. return AddDetourPluginHook(hookType, pDetour, setup, callback); +#else + return pContext->ThrowNativeError("Dynamic detours are not enabled for this mod!"); +#endif } // native bool:DHookDisableDetour(Handle:setup, bool:post, DHookCallback:callback); cell_t Native_DisableDetour(IPluginContext *pContext, const cell_t *params) { +#if defined( DHOOKS_DYNAMIC_DETOUR ) HookSetup *setup; if (!GetHandleIfValidOrError(g_HookSetupHandle, (void **)&setup, pContext, params[1])) @@ -414,6 +419,9 @@ cell_t Native_DisableDetour(IPluginContext *pContext, const cell_t *params) // Remove the callback from the hook. return RemoveDetourPluginHook(hookType, pDetour, callback); +#else + return pContext->ThrowNativeError("Dynamic detours are not enabled for this mod!"); +#endif } cell_t HookEntityImpl(IPluginContext *pContext, const cell_t *params, uint32_t callbackIndex, uint32_t removalcbIndex) diff --git a/extensions/dhooks/util.cpp b/extensions/dhooks/util.cpp index 9b08fa8a2d..e1c8df2e16 100644 --- a/extensions/dhooks/util.cpp +++ b/extensions/dhooks/util.cpp @@ -62,7 +62,11 @@ size_t GetStackParamOffset(HookParamsStruct *paramStruct, unsigned int index) continue; } #endif +#ifdef PLATFORM_X64 + offset += 8; +#else offset += paramStruct->dg->params[i].size; +#endif } return offset; } @@ -77,7 +81,9 @@ size_t GetRegisterParamOffset(HookParamsStruct *paramStruct, unsigned int index) for (int i = paramStruct->dg->params.size() - 1; i >= 0; i--) { if (paramStruct->dg->params[i].custom_register == None) + { stackSize += paramStruct->dg->params[i].size; + } } size_t offset = stackSize; diff --git a/extensions/dhooks/vfunc_call.h b/extensions/dhooks/vfunc_call.h index 1604c13e83..d12ebae447 100644 --- a/extensions/dhooks/vfunc_call.h +++ b/extensions/dhooks/vfunc_call.h @@ -200,8 +200,8 @@ SDKVector CallVFunction(DHooksCallback *dg, HookParamsStruct *paramSt { size_t offset = GetParamOffset(paramStruct, i); - void *orgAddr = *(void **)((intptr_t)paramStruct->orgParams + offset); - void *newAddr = *(void **)((intptr_t)paramStruct->newParams + offset); + void *orgAddr = (void **)((intptr_t)paramStruct->orgParams + offset); + void *newAddr = (void **)((intptr_t)paramStruct->newParams + offset); switch (dg->params.at(i).type) { @@ -291,8 +291,8 @@ string_t CallVFunction(DHooksCallback *dg, HookParamsStruct *paramStru { size_t offset = GetParamOffset(paramStruct, i); - void *orgAddr = *(void **)((intptr_t)paramStruct->orgParams + offset); - void *newAddr = *(void **)((intptr_t)paramStruct->newParams + offset); + void *orgAddr = (void **)((intptr_t)paramStruct->orgParams + offset); + void *newAddr = (void **)((intptr_t)paramStruct->newParams + offset); switch (dg->params.at(i).type) { diff --git a/extensions/dhooks/vhook.cpp b/extensions/dhooks/vhook.cpp index 1be1d528fa..d4a6f38e08 100644 --- a/extensions/dhooks/vhook.cpp +++ b/extensions/dhooks/vhook.cpp @@ -32,7 +32,11 @@ #include "vhook.h" #include "vfunc_call.h" #include "util.h" +#ifdef PLATFORM_X64 +#include "sh_asm_x86_64.h" +#else #include +#endif SourceHook::IHookManagerAutoGen *g_pHookManager = NULL; @@ -47,9 +51,111 @@ using namespace sp; #define OBJECT_OFFSET (sizeof(void *)*2) #endif -#ifndef WIN32 -void *GenerateThunk(ReturnType type) +#ifdef PLATFORM_X64 +using namespace SourceHook::Asm; +SourceHook::CPageAlloc GenBuffer::ms_Allocator(16); + +void test_func(void* rcx, void* rdx, SDKVector* r8, bool r9) +{ + //g_pSM->LogMessage(myself, "rcx(%p) - rdx(%p) - r8(%p) - r9(%p)", rcx, rdx, r8, r9); +} + +SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* hook) { + auto masm = new x64JitWriter(); + auto type = hook->returnType; + + /*if (type == ReturnType_Vector) + { + masm->push(rcx); + masm->push(rdx); + masm->push(r8); + masm->push(r9); + masm->sub(rsp, 40); + masm->mov(rax, (uintptr_t)test_func); + masm->call(rax); + masm->add(rsp, 40); + masm->pop(r9); + masm->pop(r8); + masm->pop(rdx); + masm->pop(rcx); + }*/ + + // We're going to transform rbp into our stack + masm->push(rbp); + + // Copy all the arguments into the stack + // 8 bytes per parameter + 8 bytes for potential return value + int32_t fakeStackSize = ke::Align((int32_t)hook->params.size() * 8 + 8, 16) + 8; // Add another +8 bytes to realign on 16 bytes, due to 'push rbp' earlier + int32_t parameterOffset = fakeStackSize + 8 /* push rbp */ + 8 /* return address */ + 32 /* shadow space */; + masm->sub(rsp, fakeStackSize); + masm->mov(rbp, rsp); + + static x86_64_Reg arg_reg[] = { rcx, rdx, r8, r9 }; + static x86_64_FloatReg arg_reg_float[] = { xmm0, xmm1, xmm2, xmm3 }; + + int stack_index = 0; + int fake_stack_index = 0; + int reg_index = 1; // Account |this| right away + if (type == ReturnType_Vector) { // Special return types occupy another register + masm->mov(rbp(8 * fake_stack_index), rdx); // Store return ptr at the bottom of the stack + reg_index++; + fake_stack_index++; + } + + for (int i = 0; i < hook->params.size(); i++, fake_stack_index++) { + if (reg_index < 4) { + if (hook->params[i].type == HookParamType_Float && hook->params[i].flags == PASSFLAG_BYVAL) { + masm->movsd(rbp(8 * fake_stack_index), arg_reg_float[reg_index]); + } else { + masm->mov(rax, arg_reg[reg_index]); + masm->mov(rbp(8 * fake_stack_index), rax); + } + reg_index++; + } else { + masm->mov(rax, rbp(parameterOffset + 8 * stack_index)); + masm->mov(rbp(8 * fake_stack_index), rax); + stack_index++; + } + } + + //masm->mov(rbp(8 * 2), 0x7777777777777777); + //masm->mov(rbp(8 * 1), 0xDEADBEEFDEADBEEF); + + // Setup 2nd parameter (our fake stack) + masm->mov(rdx, rbp); + + if (type == ReturnType_Float) + { + masm->mov(rax, (uintptr_t)Callback_float); + } + else if (type == ReturnType_Vector) + { + masm->mov(rax, (uintptr_t)Callback_vector); + } + /*else if (type == ReturnType_String) + { + masm->mov(rax, (uintptr_t)Callback_stringt); + }*/ + else + { + masm->mov(rax, (uintptr_t)Callback); + } + masm->sub(rsp, 40); + masm->call(rax); + masm->add(rsp, 40); + + masm->add(rsp, fakeStackSize); + masm->pop(rbp); + masm->retn(); + + masm->SetRE(); + return masm; +} +#elif !defined( WIN32 ) +void *GenerateThunk(HookSetup* hook) +{ + auto type = hook->returnType; sp::MacroAssembler masm; static const size_t kStackNeeded = (2) * 4; // 2 args max static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8; @@ -97,8 +203,9 @@ void *GenerateThunk(ReturnType type) } #else // HUGE THANKS TO BAILOPAN (dvander)! -void *GenerateThunk(ReturnType type) +void *GenerateThunk(HookSetup* hook) { + auto type = hook->returnType; sp::MacroAssembler masm; static const size_t kStackNeeded = (3 + 1) * 4; // 3 args max, 1 locals max static const size_t kReserve = ke::Align(kStackNeeded + 8, 16) - 8; @@ -138,7 +245,7 @@ void *GenerateThunk(ReturnType type) DHooksManager::DHooksManager(HookSetup *setup, void *iface, IPluginFunction *remove_callback, IPluginFunction *plugincb, bool post) { - this->callback = MakeHandler(setup->returnType); + this->callback = MakeHandler(setup); this->hookid = 0; this->remove_callback = remove_callback; this->callback->offset = setup->offset; @@ -232,11 +339,11 @@ SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type) size_t GetStackArgsSize(DHooksCallback *dg) { size_t res = GetParamsSize(dg); - #ifdef WIN32 +#ifdef WIN32 if(dg->returnType == ReturnType_Vector)//Account for result vector ptr. - #else +#else if(dg->returnType == ReturnType_Vector || dg->returnType == ReturnType_String) - #endif +#endif { res += OBJECT_OFFSET; } @@ -272,11 +379,11 @@ HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t arg { HookParamsStruct *params = new HookParamsStruct(); params->dg = dg; - #ifdef WIN32 +#ifdef WIN32 if(dg->returnType != ReturnType_Vector) - #else +#else if(dg->returnType != ReturnType_Vector && dg->returnType != ReturnType_String) - #endif +#endif { params->orgParams = (void **)malloc(argStackSize); memcpy(params->orgParams, argStack, argStackSize); @@ -284,7 +391,7 @@ HookParamsStruct *GetParamStruct(DHooksCallback *dg, void **argStack, size_t arg else //Offset result ptr { params->orgParams = (void **)malloc(argStackSize-OBJECT_OFFSET); - memcpy(params->orgParams, argStack+OBJECT_OFFSET, argStackSize-OBJECT_OFFSET); + memcpy(params->orgParams, (void*)((uintptr_t)argStack + OBJECT_OFFSET), argStackSize - OBJECT_OFFSET); } size_t paramsSize = GetParamsSize(dg); @@ -388,11 +495,14 @@ cell_t GetThisPtr(void *iface, ThisPointerType type) return -1; return gamehelpers->EntityToBCompatRef((CBaseEntity *)iface); } - +#ifdef PLATFORM_X64 + return g_pSM->ToPseudoAddress(iface); +#else return (cell_t)iface; +#endif } -#ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) void *Callback(DHooksCallback *dg, void **argStack, size_t *argsizep) #else void *Callback(DHooksCallback *dg, void **argStack) @@ -403,11 +513,12 @@ void *Callback(DHooksCallback *dg, void **argStack) Handle_t rHndl; Handle_t pHndl; - #ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) *argsizep = GetStackArgsSize(dg); - #else +#else size_t argsize = GetStackArgsSize(dg); - #endif +#endif + //g_pSM->LogMessage(myself, "[DEFAULT]DHooksCallback(%p) argStack(%p) - argsize(%d)", dg, argStack, argsize); if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { @@ -430,15 +541,15 @@ void *Callback(DHooksCallback *dg, void **argStack) dg->plugin_callback->PushCell(rHndl); } - #ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) if(*argsizep > 0) { paramStruct = GetParamStruct(dg, argStack, *argsizep); - #else +#else if(argsize > 0) { paramStruct = GetParamStruct(dg, argStack, argsize); - #endif +#endif pHndl = handlesys->CreateHandle(g_HookParamsHandle, paramStruct, dg->plugin_callback->GetParentRuntime()->GetDefaultContext()->GetIdentity(), myself->GetIdentity(), NULL); if(!pHndl) { @@ -575,7 +686,7 @@ void *Callback(DHooksCallback *dg, void **argStack) } return ret; } -#ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) float Callback_float(DHooksCallback *dg, void **argStack, size_t *argsizep) #else float Callback_float(DHooksCallback *dg, void **argStack) @@ -586,11 +697,12 @@ float Callback_float(DHooksCallback *dg, void **argStack) Handle_t rHndl; Handle_t pHndl; - #ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) *argsizep = GetStackArgsSize(dg); - #else +#else size_t argsize = GetStackArgsSize(dg); - #endif +#endif + //g_pSM->LogMessage(myself, "[FLOAT]DHooksCallback(%p) argStack(%p) - argsize(%d)", dg, argStack, argsize); if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { @@ -612,7 +724,7 @@ float Callback_float(DHooksCallback *dg, void **argStack) } dg->plugin_callback->PushCell(rHndl); - #ifdef WIN32 + #if defined( WIN32 ) && !defined( PLATFORM_X64 ) if(*argsizep > 0) { paramStruct = GetParamStruct(dg, argStack, *argsizep); @@ -729,24 +841,25 @@ float Callback_float(DHooksCallback *dg, void **argStack) } return *(float *)ret; } -#ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) SDKVector *Callback_vector(DHooksCallback *dg, void **argStack, size_t *argsizep) #else SDKVector *Callback_vector(DHooksCallback *dg, void **argStack) #endif { - SDKVector *vec_result = (SDKVector *)argStack[0]; // Save the result + SDKVector *vec_result = (SDKVector *)argStack[0]; HookReturnStruct *returnStruct = NULL; HookParamsStruct *paramStruct = NULL; Handle_t rHndl; Handle_t pHndl; - #ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) *argsizep = GetStackArgsSize(dg); - #else +#else size_t argsize = GetStackArgsSize(dg); - #endif +#endif + //g_pSM->LogMessage(myself, "[VECTOR]DHooksCallback(%p) argStack(%p) - argsize(%d) - params count %d", dg, argStack, argsize, dg->params.size()); if(dg->thisType == ThisPointer_CBaseEntity || dg->thisType == ThisPointer_Address) { @@ -768,7 +881,7 @@ SDKVector *Callback_vector(DHooksCallback *dg, void **argStack) } dg->plugin_callback->PushCell(rHndl); - #ifdef WIN32 + #if defined( WIN32 ) && !defined( PLATFORM_X64 ) if(*argsizep > 0) { paramStruct = GetParamStruct(dg, argStack, *argsizep); diff --git a/extensions/dhooks/vhook.h b/extensions/dhooks/vhook.h index 6146d1ad6a..b58f9c4ff1 100644 --- a/extensions/dhooks/vhook.h +++ b/extensions/dhooks/vhook.h @@ -39,6 +39,10 @@ #include #include +#ifdef PLATFORM_X64 +#include "sh_asm_x86_64.h" +#endif + enum CallingConvention { CallConv_CDECL, @@ -163,11 +167,20 @@ class DHooksInfo class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo { public: + DHooksCallback() + { + //g_pSM->LogMessage(myself, "DHooksCallback(%p)", this); + } + virtual bool IsEqual(ISHDelegate *pOtherDeleg){return false;}; virtual void DeleteThis() { *(void ***)this = this->oldvtable; +#ifdef PLATFORM_X64 + delete callThunk; +#else g_pSM->GetScriptingEngine()->FreePageMemory(this->newvtable[2]); +#endif delete this->newvtable; delete this; }; @@ -175,9 +188,12 @@ class DHooksCallback : public SourceHook::ISHDelegate, public DHooksInfo public: void **newvtable; void **oldvtable; +#ifdef PLATFORM_X64 + SourceHook::Asm::x64JitWriter* callThunk; +#endif }; -#ifdef WIN32 +#if defined( WIN32 ) && !defined( PLATFORM_X64 ) void *Callback(DHooksCallback *dg, void **stack, size_t *argsizep); float Callback_float(DHooksCallback *dg, void **stack, size_t *argsizep); SDKVector *Callback_vector(DHooksCallback *dg, void **stack, size_t *argsizep); @@ -192,20 +208,6 @@ bool SetupHookManager(ISmmAPI *ismm); void CleanupHooks(IPluginContext *pContext = NULL); size_t GetParamTypeSize(HookParamType type); SourceHook::PassInfo::PassType GetParamTypePassType(HookParamType type); -void *GenerateThunk(ReturnType type); - -static DHooksCallback *MakeHandler(ReturnType type) -{ - DHooksCallback *dg = new DHooksCallback(); - dg->returnType = type; - dg->oldvtable = *(void ***)dg; - dg->newvtable = new void *[3]; - dg->newvtable[0] = dg->oldvtable[0]; - dg->newvtable[1] = dg->oldvtable[1]; - dg->newvtable[2] = GenerateThunk(type); - *(void ***)dg = dg->newvtable; - return dg; -} class HookParamsStruct { @@ -276,6 +278,37 @@ class HookSetup HookMethod hookMethod; }; +#ifdef PLATFORM_X64 +SourceHook::Asm::x64JitWriter* GenerateThunk(HookSetup* type); +static DHooksCallback *MakeHandler(HookSetup* hook) +{ + DHooksCallback *dg = new DHooksCallback(); + dg->returnType = hook->returnType; + dg->oldvtable = *(void ***)dg; + dg->newvtable = new void *[3]; + dg->newvtable[0] = dg->oldvtable[0]; + dg->newvtable[1] = dg->oldvtable[1]; + dg->callThunk = GenerateThunk(hook); + dg->newvtable[2] = dg->callThunk->GetData(); + *(void ***)dg = dg->newvtable; + return dg; +} +#else +void *GenerateThunk(HookSetup* type); +static DHooksCallback *MakeHandler(HookSetup* hook) +{ + DHooksCallback *dg = new DHooksCallback(); + dg->returnType = hook->returnType; + dg->oldvtable = *(void ***)dg; + dg->newvtable = new void *[3]; + dg->newvtable[0] = dg->oldvtable[0]; + dg->newvtable[1] = dg->oldvtable[1]; + dg->newvtable[2] = GenerateThunk(hook); + *(void ***)dg = dg->newvtable; + return dg; +} +#endif + class DHooksManager { public: diff --git a/extensions/sdkhooks/extension.cpp b/extensions/sdkhooks/extension.cpp index 673caba03c..3a457fb51c 100644 --- a/extensions/sdkhooks/extension.cpp +++ b/extensions/sdkhooks/extension.cpp @@ -151,6 +151,7 @@ CUtlVector *EntListeners() /** * IServerGameDLL & IVEngineServer Hooks */ +SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, 0, bool, const char *, const char *, const char *, const char *, bool, bool); #ifdef GAMEDESC_CAN_CHANGE SH_DECL_HOOK0(IServerGameDLL, GetGameDescription, SH_NOATTRIB, 0, const char *); @@ -247,6 +248,8 @@ bool SDKHooks::SDK_OnLoad(char *error, size_t maxlength, bool late) sharesys->AddCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD"); sharesys->AddCapabilityProvider(myself, this, "SDKHook_LogicalEntSupport"); + SH_ADD_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SDKHooks::LevelShutdown), false); + playerhelpers->AddClientListener(&g_Interface); plsys->AddPluginsListener(&g_Interface); @@ -365,7 +368,9 @@ void SDKHooks::SDK_OnUnload() forwards->ReleaseForward(g_pOnLevelInit); plsys->RemovePluginsListener(&g_Interface); - + + SH_REMOVE_HOOK(IServerGameDLL, LevelShutdown, gamedll, SH_MEMBER(this, &SDKHooks::LevelShutdown), true); + playerhelpers->RemoveClientListener(&g_Interface); sharesys->DropCapabilityProvider(myself, this, "SDKHook_DmgCustomInOTD"); @@ -445,6 +450,24 @@ void SDKHooks::OnClientDisconnecting(int client) HandleEntityDeleted(pEntity); } +void SDKHooks::LevelShutdown() +{ +#if defined PLATFORM_LINUX + for (size_t type = 0; type < SDKHook_MAXHOOKS; ++type) + { + std::vector &vtablehooklist = g_HookList[type]; + for (size_t listentry = 0; listentry < vtablehooklist.size(); ++listentry) + { + std::vector &pawnhooks = vtablehooklist[listentry]->hooks; + pawnhooks.clear(); + + delete vtablehooklist[listentry]; + } + vtablehooklist.clear(); + } +#endif +} + void SDKHooks::AddEntityListener(ISMEntityListener *listener) { m_EntListeners.push_back(listener); @@ -591,11 +614,16 @@ HookReturn SDKHooks::Hook(int entity, SDKHookType type, IPluginFunction *callbac if (!!strcmp(g_HookTypes[type].dtReq, "")) { - IServerUnknown *pUnk = (IServerUnknown *)pEnt; + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEnt); + if (pServerClass == nullptr) + { + return HookRet_BadEntForHookType; + } - IServerNetworkable *pNet = pUnk->GetNetworkable(); - if (pNet && !UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, g_HookTypes[type].dtReq)) + if (!UTIL_ContainsDataTable(pServerClass->m_pTable, g_HookTypes[type].dtReq)) + { return HookRet_BadEntForHookType; + } } size_t entry; @@ -791,12 +819,14 @@ void SDKHooks::Unhook(CBaseEntity *pEntity) entry--; } +#if !defined PLATFORM_LINUX if (pawnhooks.size() == 0) { delete vtablehooklist[listentry]; vtablehooklist.erase(vtablehooklist.begin() + listentry); listentry--; } +#endif } } } @@ -820,12 +850,14 @@ void SDKHooks::Unhook(IPluginContext *pContext) entry--; } +#if !defined PLATFORM_LINUX if (pawnhooks.size() == 0) { delete vtablehooklist[listentry]; vtablehooklist.erase(vtablehooklist.begin() + listentry); listentry--; } +#endif } } } @@ -862,12 +894,14 @@ void SDKHooks::Unhook(int entity, SDKHookType type, IPluginFunction *pCallback) entry--; } +#if !defined PLATFORM_LINUX if (pawnhooks.size() == 0) { delete vtablehooklist[listentry]; vtablehooklist.erase(vtablehooklist.begin() + listentry); listentry--; } +#endif break; } diff --git a/extensions/sdkhooks/extension.h b/extensions/sdkhooks/extension.h index 0a9b326bad..1168fe9135 100644 --- a/extensions/sdkhooks/extension.h +++ b/extensions/sdkhooks/extension.h @@ -259,6 +259,8 @@ class SDKHooks : virtual void AddEntityListener(ISMEntityListener *listener); virtual void RemoveEntityListener(ISMEntityListener *listener); +public: // IServerGameDLL + void LevelShutdown(); private: SourceHook::List m_EntListeners; diff --git a/extensions/sdkhooks/natives.cpp b/extensions/sdkhooks/natives.cpp index e801747bda..526bc68622 100644 --- a/extensions/sdkhooks/natives.cpp +++ b/extensions/sdkhooks/natives.cpp @@ -60,15 +60,15 @@ cell_t Native_Hook(IPluginContext *pContext, const cell_t *params) break; case HookRet_BadEntForHookType: { - CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(params[1]); - const char *pClassname = pEnt ? gamehelpers->GetEntityClassname(pEnt) : NULL; - if (!pClassname) - { - pContext->ThrowNativeError("Hook type not valid for this type of entity (%i).", entity); - } - else - { - pContext->ThrowNativeError("Hook type not valid for this type of entity (%i/%s)", entity, pClassname); + CBaseEntity *pEnt = gamehelpers->ReferenceToEntity(params[1]); + const char *pClassname = pEnt ? gamehelpers->GetEntityClassname(pEnt) : NULL; + if (!pClassname) + { + pContext->ThrowNativeError("Hook type not valid for this type of entity (%i).", entity); + } + else + { + pContext->ThrowNativeError("Hook type not valid for this type of entity (%i/%s)", entity, pClassname); } break; @@ -185,9 +185,9 @@ cell_t Native_TakeDamage(IPluginContext *pContext, const cell_t *params) if (!pCall) { int offset; - if (!g_pGameConf->GetOffset("OnTakeDamage", &offset)) - { - return pContext->ThrowNativeError("Could not find OnTakeDamage offset"); + if (!g_pGameConf->GetOffset("OnTakeDamage", &offset)) + { + return pContext->ThrowNativeError("Could not find OnTakeDamage offset"); } PassInfo pass[2]; @@ -230,10 +230,13 @@ cell_t Native_DropWeapon(IPluginContext *pContext, const cell_t *params) if (!pWeapon) return pContext->ThrowNativeError("Invalid entity index %d for weapon", params[2]); - IServerUnknown *pUnk = (IServerUnknown *)pWeapon; - IServerNetworkable *pNet = pUnk->GetNetworkable(); - - if (!UTIL_ContainsDataTable(pNet->GetServerClass()->m_pTable, "DT_BaseCombatWeapon")) + ServerClass *pClass = gamehelpers->FindEntityServerClass(pWeapon); + if (pClass == nullptr) + { + return pContext->ThrowNativeError("Failed to retrieve entity %d server class!", params[2]); + } + + if (!UTIL_ContainsDataTable(pClass->m_pTable, "DT_BaseCombatWeapon")) return pContext->ThrowNativeError("Entity index %d is not a weapon", params[2]); sm_sendprop_info_t spi; @@ -291,9 +294,9 @@ cell_t Native_DropWeapon(IPluginContext *pContext, const cell_t *params) if (!pCall) { int offset; - if (!g_pGameConf->GetOffset("Weapon_Drop", &offset)) - { - return pContext->ThrowNativeError("Could not find Weapon_Drop offset"); + if (!g_pGameConf->GetOffset("Weapon_Drop", &offset)) + { + return pContext->ThrowNativeError("Could not find Weapon_Drop offset"); } PassInfo pass[3]; diff --git a/extensions/sdktools/AMBuilder b/extensions/sdktools/AMBuilder index 0b5dca0164..e71c365718 100644 --- a/extensions/sdktools/AMBuilder +++ b/extensions/sdktools/AMBuilder @@ -24,15 +24,7 @@ project.sources += [ 'hooks.cpp', 'gamerulesnatives.cpp', 'vstringtable.cpp', - '../../public/smsdk_ext.cpp', - '../../public/CDetour/detours.cpp', - '../../public/asm/asm.c', - '../../public/libudis86/decode.c', - '../../public/libudis86/itab.c', - '../../public/libudis86/syn-att.c', - '../../public/libudis86/syn-intel.c', - '../../public/libudis86/syn.c', - '../../public/libudis86/udis86.c', + '../../public/smsdk_ext.cpp' ] for sdk_name in SM.sdks: @@ -45,18 +37,20 @@ for sdk_name in SM.sdks: continue binary = SM.HL2ExtConfig(project, builder, cxx, 'sdktools.ext.' + sdk['extension'], sdk) + SM.AddCDetour(binary) + binary.compiler.cxxincludes += [ os.path.join(builder.sourcePath, 'public', 'jit'), os.path.join(builder.sourcePath, 'public', 'jit', 'x86'), ] if sdk['name'] in ('episode1', 'darkm'): - binary.compiler.cxxincludes += [os.path.join(builder.options.hl2sdk_root, sdk['path'], 'game_shared')] - binary.compiler.cxxincludes += [os.path.join(builder.options.hl2sdk_root, sdk['path'], 'dlls')] + binary.compiler.cxxincludes += [os.path.join(sdk['path'], 'game_shared')] + binary.compiler.cxxincludes += [os.path.join(sdk['path'], 'dlls')] else: binary.compiler.cxxincludes += [ - os.path.join(builder.options.hl2sdk_root, sdk['path'], 'game', 'shared'), - os.path.join(builder.options.hl2sdk_root, sdk['path'], 'game', 'server'), + os.path.join(sdk['path'], 'game', 'shared'), + os.path.join(sdk['path'], 'game', 'server'), ] #binary.sources += [os.path.join(builder.options.hl2sdk_root, sdk['path'], 'game', 'server', 'variant_t.cpp')] diff --git a/extensions/sdktools/gamerulesnatives.cpp b/extensions/sdktools/gamerulesnatives.cpp index 07f4477a71..ca6c8728bc 100644 --- a/extensions/sdktools/gamerulesnatives.cpp +++ b/extensions/sdktools/gamerulesnatives.cpp @@ -45,26 +45,27 @@ static CBaseEntity *FindEntityByNetClass(int start, const char *classname) int maxEntities = gpGlobals->maxEntities; for (int i = start; i < maxEntities; i++) { - edict_t *current = gamehelpers->EdictOfIndex(i); - if (current == NULL || current->IsFree()) - continue; - - IServerNetworkable *network = current->GetNetworkable(); - if (network == NULL) + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); + if (pEntity == nullptr) + { continue; + } - IHandleEntity *pHandleEnt = network->GetEntityHandle(); - if (pHandleEnt == NULL) + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEntity); + if (pServerClass == nullptr) + { continue; + } + - ServerClass *sClass = network->GetServerClass(); - const char *name = sClass->GetName(); - + const char *name = pServerClass->GetName(); if (!strcmp(name, classname)) - return gamehelpers->ReferenceToEntity(gamehelpers->IndexOfEdict(current)); + { + return pEntity; + } } - return NULL; + return nullptr; } static CBaseEntity* GetGameRulesProxyEnt() diff --git a/extensions/sdktools/hooks.cpp b/extensions/sdktools/hooks.cpp index 79094702b3..706b478d69 100644 --- a/extensions/sdktools/hooks.cpp +++ b/extensions/sdktools/hooks.cpp @@ -234,7 +234,7 @@ void CHookManager::OnClientConnected(int client) } } - int hookid = SH_ADD_VPHOOK(IClientMessageHandler, ProcessVoiceData, (IClientMessageHandler *)((intptr_t)(pClient) + 4), SH_MEMBER(this, &CHookManager::ProcessVoiceData), true); + int hookid = SH_ADD_VPHOOK(IClientMessageHandler, ProcessVoiceData, (IClientMessageHandler *)((intptr_t)(pClient) + sizeof(void *)), SH_MEMBER(this, &CHookManager::ProcessVoiceData), true); hook.SetHookID(hookid); netProcessVoiceData.push_back(new CVTableHook(hook)); } @@ -584,7 +584,7 @@ bool CHookManager::SendFile(const char *filename, unsigned int transferID) #if !defined CLIENTVOICE_HOOK_SUPPORT bool CHookManager::ProcessVoiceData(CLC_VoiceData *msg) { - IClient *pClient = (IClient *)((intptr_t)(META_IFACEPTR(IClient)) - 4); + IClient *pClient = (IClient *)((intptr_t)(META_IFACEPTR(IClient)) - sizeof(void *)); if (pClient == NULL) { return true; diff --git a/extensions/sdktools/output.h b/extensions/sdktools/output.h index d3e11e4bc1..02ec9da5d4 100644 --- a/extensions/sdktools/output.h +++ b/extensions/sdktools/output.h @@ -128,7 +128,6 @@ class EntityOutputManager : public IPluginsListener int HookCount; - patch_t info_restore; void *info_address; void *info_callback; }; diff --git a/extensions/sdktools/teamnatives.cpp b/extensions/sdktools/teamnatives.cpp index 6334ca5e48..8f770fe5bd 100644 --- a/extensions/sdktools/teamnatives.cpp +++ b/extensions/sdktools/teamnatives.cpp @@ -50,19 +50,20 @@ void InitTeamNatives() int edictCount = gpGlobals->maxEntities; - for (int i=0; iIsFree()) + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); + if (pEntity == nullptr) { continue; } - if (!pEdict->GetNetworkable()) + + ServerClass *pClass = gamehelpers->FindEntityServerClass(pEntity); + if (pClass == nullptr) { continue; } - - ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass(); + if (FindNestedDataTable(pClass->m_pTable, "DT_Team")) { SendProp *pTeamNumProp = g_pGameHelpers->FindInSendTable(pClass->GetName(), "m_iTeamNum"); @@ -70,15 +71,14 @@ void InitTeamNatives() if (pTeamNumProp != NULL) { int offset = pTeamNumProp->GetOffset(); - CBaseEntity *pEnt = pEdict->GetUnknown()->GetBaseEntity(); - int TeamIndex = *(int *)((unsigned char *)pEnt + offset); + int TeamIndex = *(int *)((unsigned char *)pEntity + offset); if (TeamIndex >= (int)g_Teams.size()) { g_Teams.resize(TeamIndex+1); } g_Teams[TeamIndex].ClassName = pClass->GetName(); - g_Teams[TeamIndex].pEnt = pEnt; + g_Teams[TeamIndex].pEnt = pEntity; } } } diff --git a/extensions/sdktools/vdecoder.cpp b/extensions/sdktools/vdecoder.cpp index 7bdf2ef0eb..881fa667a9 100644 --- a/extensions/sdktools/vdecoder.cpp +++ b/extensions/sdktools/vdecoder.cpp @@ -396,15 +396,17 @@ DataStatus DecodeValveParam(IPluginContext *pContext, if (index >= 1 && index <= playerhelpers->GetMaxClients()) { IGamePlayer *player = playerhelpers->GetGamePlayer(index); - if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME) - && !player->IsConnected()) - { + + if(!player->IsConnected()) { pContext->ThrowNativeError("Client %d is not connected", param); return Data_Fail; - } else if (!player->IsInGame()) { + } + + if(!(data->decflags & VDECODE_FLAG_ALLOWNOTINGAME) && !player->IsInGame()) { pContext->ThrowNativeError("Client %d is not in game", param); return Data_Fail; } + pEntity = gamehelpers->ReferenceToEntity(param); } else if (param == -1) { if (data->decflags & VDECODE_FLAG_ALLOWNULL) @@ -441,15 +443,17 @@ DataStatus DecodeValveParam(IPluginContext *pContext, if (index >= 1 && index <= playerhelpers->GetMaxClients()) { IGamePlayer *player = playerhelpers->GetGamePlayer(index); - if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME) - && !player->IsConnected()) - { + + if(!player->IsConnected()) { pContext->ThrowNativeError("Client %d is not connected", param); return Data_Fail; - } else if (!player->IsInGame()) { + } + + if(!(data->decflags & VDECODE_FLAG_ALLOWNOTINGAME) && !player->IsInGame()) { pContext->ThrowNativeError("Client %d is not in game", param); return Data_Fail; } + pEntity = gamehelpers->ReferenceToEntity(param); } else if (param == -1) { if (data->decflags & VDECODE_FLAG_ALLOWNULL) @@ -493,15 +497,17 @@ DataStatus DecodeValveParam(IPluginContext *pContext, if (param >= 1 && param <= playerhelpers->GetMaxClients()) { IGamePlayer *player = playerhelpers->GetGamePlayer(param); - if ((data->decflags & VDECODE_FLAG_ALLOWNOTINGAME) - && !player->IsConnected()) - { + + if(!player->IsConnected()) { pContext->ThrowNativeError("Client %d is not connected", param); return Data_Fail; - } else if (!player->IsInGame()) { + } + + if(!(data->decflags & VDECODE_FLAG_ALLOWNOTINGAME) && !player->IsInGame()) { pContext->ThrowNativeError("Client %d is not in game", param); return Data_Fail; } + pEdict = player->GetEdict(); } else if (param == -1) { if (data->decflags & VDECODE_FLAG_ALLOWNULL) diff --git a/extensions/sdktools/vglobals.cpp b/extensions/sdktools/vglobals.cpp index 046fe75c5a..acfe10deac 100644 --- a/extensions/sdktools/vglobals.cpp +++ b/extensions/sdktools/vglobals.cpp @@ -321,28 +321,23 @@ void GetResourceEntity() { int edictCount = gpGlobals->maxEntities; - for (int i=0; iIsFree()) - { - continue; - } - if (!pEdict->GetNetworkable()) + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); + if (pEntity == nullptr) { continue; } - IHandleEntity *pHandleEnt = pEdict->GetNetworkable()->GetEntityHandle(); - if (!pHandleEnt) + ServerClass *pClass = gamehelpers->FindEntityServerClass(pEntity); + if (pClass == nullptr) { continue; } - - ServerClass *pClass = pEdict->GetNetworkable()->GetServerClass(); + if (FindNestedDataTable(pClass->m_pTable, "DT_PlayerResource")) { - g_ResourceEntity = pHandleEnt->GetRefEHandle(); + g_ResourceEntity = ((IHandleEntity *)pEntity)->GetRefEHandle(); break; } } diff --git a/extensions/sdktools/vhelpers.cpp b/extensions/sdktools/vhelpers.cpp index 7d5c5545d0..0dfbc08c8a 100644 --- a/extensions/sdktools/vhelpers.cpp +++ b/extensions/sdktools/vhelpers.cpp @@ -753,8 +753,8 @@ CEntityFactoryDictionary *GetEntityFactoryDictionary() int32_t funcOffset = *(int32_t *)((intptr_t)addr + offset); // Get real address of function - // Address of signature + offset of relative offset + sizeof(int32_t) offset + relative offset - addr = (void *)((intptr_t)addr + offset + 4 + funcOffset); + // Address of signature + offset of relative offset + pointer size + relative offset + addr = (void *)((intptr_t)addr + offset + sizeof(void *) + funcOffset); } pWrapper = g_pBinTools->CreateCall(addr, CallConv_Cdecl, &retData, NULL, 0); diff --git a/extensions/sdktools/vnatives.cpp b/extensions/sdktools/vnatives.cpp index be41f65e05..e3d71ff3be 100644 --- a/extensions/sdktools/vnatives.cpp +++ b/extensions/sdktools/vnatives.cpp @@ -1689,7 +1689,12 @@ static cell_t LookupEntityAttachment(IPluginContext* pContext, const cell_t* par CBaseEntity* pEntity; ENTINDEX_TO_CBASEENTITY(params[1], pEntity); - ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass(); + ServerClass* pClass = gamehelpers->FindEntityServerClass(pEntity); + if (pClass == nullptr) + { + return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", gamehelpers->ReferenceToIndex(params[1]), params[1]); + } + if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating")) { return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]); @@ -1735,7 +1740,12 @@ static cell_t GetEntityAttachment(IPluginContext* pContext, const cell_t* params CBaseEntity* pEntity; ENTINDEX_TO_CBASEENTITY(params[1], pEntity); - ServerClass* pClass = ((IServerUnknown*)pEntity)->GetNetworkable()->GetServerClass(); + ServerClass* pClass = gamehelpers->FindEntityServerClass(pEntity); + if (pClass == nullptr) + { + return pContext->ThrowNativeError("Failed to retrieve entity %d (%d) server class!", gamehelpers->ReferenceToIndex(params[1]), params[1]); + } + if (!FindNestedDataTable(pClass->m_pTable, "DT_BaseAnimating")) { return pContext->ThrowNativeError("Entity %d (%d) is not a CBaseAnimating", gamehelpers->ReferenceToIndex(params[1]), params[1]); diff --git a/extensions/tf2/AMBuilder b/extensions/tf2/AMBuilder index 2b3e953645..ffd8f1e168 100644 --- a/extensions/tf2/AMBuilder +++ b/extensions/tf2/AMBuilder @@ -8,6 +8,7 @@ if 'tf2' in SM.sdks: if not cxx.target.arch in sdk['platforms'][cxx.target.platform]: continue binary = SM.HL2Library(builder, cxx, 'game.tf2.ext.' + sdk['extension'], sdk) + SM.AddCDetour(binary) binary.sources += [ 'extension.cpp', 'natives.cpp', @@ -18,15 +19,7 @@ if 'tf2' in SM.sdks: 'teleporter.cpp', 'gameplayrules.cpp', 'conditions.cpp', - '../../public/smsdk_ext.cpp', - '../../public/CDetour/detours.cpp', - '../../public/asm/asm.c', - '../../public/libudis86/decode.c', - '../../public/libudis86/itab.c', - '../../public/libudis86/syn-att.c', - '../../public/libudis86/syn-intel.c', - '../../public/libudis86/syn.c', - '../../public/libudis86/udis86.c', + '../../public/smsdk_ext.cpp' ] binary.compiler.defines += ['HAVE_STRING_H'] SM.extensions += [builder.Add(binary)] diff --git a/extensions/tf2/criticals.cpp b/extensions/tf2/criticals.cpp index dac519cbe1..3a4621f773 100644 --- a/extensions/tf2/criticals.cpp +++ b/extensions/tf2/criticals.cpp @@ -76,16 +76,21 @@ bool CritManager::TryEnable() for (size_t i = playerhelpers->GetMaxClients() + 1; i < MAX_EDICTS; ++i) { CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); - if (pEntity == NULL) + if (pEntity == nullptr) + { continue; + } - IServerUnknown *pUnknown = (IServerUnknown *)pEntity; - IServerNetworkable *pNetworkable = pUnknown->GetNetworkable(); - if (!pNetworkable) + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEntity); + if (pServerClass == nullptr) + { continue; + } - if (!UTIL_ContainsDataTable(pNetworkable->GetServerClass()->m_pTable, TF_WEAPON_DATATABLE)) + if (!UTIL_ContainsDataTable(pServerClass->m_pTable, TF_WEAPON_DATATABLE)) + { continue; + } SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelper), false); SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelperNoCrits), false); @@ -116,15 +121,20 @@ void CritManager::Disable() void CritManager::OnEntityCreated(CBaseEntity *pEntity, const char *classname) { if (!m_enabled) + { return; + } - IServerUnknown *pUnknown = (IServerUnknown *)pEntity; - IServerNetworkable *pNetworkable = pUnknown->GetNetworkable(); - if (!pNetworkable) + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEntity); + if (pServerClass == nullptr) + { return; + } - if (!UTIL_ContainsDataTable(pNetworkable->GetServerClass()->m_pTable, TF_WEAPON_DATATABLE)) + if (!UTIL_ContainsDataTable(pServerClass->m_pTable, TF_WEAPON_DATATABLE)) + { return; + } SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelper, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelper), false); SH_ADD_MANUALHOOK(CalcIsAttackCriticalHelperNoCrits, pEntity, SH_MEMBER(&g_CritManager, &CritManager::Hook_CalcIsAttackCriticalHelperNoCrits), false); @@ -164,11 +174,9 @@ bool CritManager::Hook_CalcIsAttackCriticalHelpers(bool noCrits) { CBaseEntity *pWeapon = META_IFACEPTR(CBaseEntity); - // If there's an invalid ent or invalid networkable here, we've got issues elsewhere. - - IServerNetworkable *pNetWeapon = ((IServerUnknown *)pWeapon)->GetNetworkable(); - ServerClass *pServerClass = pNetWeapon->GetServerClass(); - if (!pServerClass) + // If there's an invalid ent or invalid server class here, we've got issues elsewhere. + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pWeapon); + if (pServerClass == nullptr) { g_pSM->LogError(myself, "Invalid server class on weapon."); RETURN_META_VALUE(MRES_IGNORED, false); diff --git a/extensions/tf2/extension.cpp b/extensions/tf2/extension.cpp index ce745248f8..620eec5697 100644 --- a/extensions/tf2/extension.cpp +++ b/extensions/tf2/extension.cpp @@ -435,23 +435,19 @@ int FindEntityByNetClass(int start, const char *classname) for (int i = ((start != -1) ? start : 0); i < gpGlobals->maxEntities; i++) { - current = engine->PEntityOfEntIndex(i); - if (current == NULL || current->IsFree()) + CBaseEntity *pEntity = gamehelpers->ReferenceToEntity(i); + if (pEntity == nullptr) { continue; } - IServerNetworkable *network = current->GetNetworkable(); - - if (network == NULL) + ServerClass *pServerClass = gamehelpers->FindEntityServerClass(pEntity); + if (pServerClass == nullptr) { continue; } - - ServerClass *sClass = network->GetServerClass(); - const char *name = sClass->GetName(); - + const char *name = pServerClass->GetName(); if (strcmp(name, classname) == 0) { return i; diff --git a/gamedata/sdkhooks.games/engine.ep2v.txt b/gamedata/sdkhooks.games/engine.ep2v.txt index 9a764cf4bb..7c524c75ac 100644 --- a/gamedata/sdkhooks.games/engine.ep2v.txt +++ b/gamedata/sdkhooks.games/engine.ep2v.txt @@ -37,7 +37,7 @@ "GetMaxHealth" { "windows" "122" - "windows64" "123" + "windows64" "122" "linux" "123" "linux64" "123" } diff --git a/plugins/include/files.inc b/plugins/include/files.inc index 78efd65cc2..a54f199643 100644 --- a/plugins/include/files.inc +++ b/plugins/include/files.inc @@ -601,6 +601,15 @@ native bool CreateDirectory(const char[] path, int mode=FPERM_O_READ|FPERM_O_EXE */ native bool SetFilePermissions(const char[] path, int mode); +/** + * Retrieves a file or directories permissions. + * + * @param path Path to the file. + * @param mode Variable to store the permissions in. + * @return True on success, false otherwise. + */ +native bool GetFilePermissions(const char[] path, int &mode); + /** * Returns a file timestamp as a unix timestamp. * diff --git a/plugins/include/tf2_stocks.inc b/plugins/include/tf2_stocks.inc index 71303325aa..f9782848ab 100644 --- a/plugins/include/tf2_stocks.inc +++ b/plugins/include/tf2_stocks.inc @@ -399,6 +399,7 @@ stock TFClassType TF2_GetPlayerClass(int client) */ stock void TF2_SetPlayerClass(int client, TFClassType classType, bool weapons=true, bool persistent=true) { + #pragma unused weapons SetEntProp(client, Prop_Send, "m_iClass", view_as(classType)); if (persistent) diff --git a/public/CDetour/detours.cpp b/public/CDetour/detours.cpp index 822bba3c18..0fe27c7213 100644 --- a/public/CDetour/detours.cpp +++ b/public/CDetour/detours.cpp @@ -1,92 +1,9 @@ -/** -* vim: set ts=4 : -* ============================================================================= -* SourceMod -* Copyright (C) 2004-2010 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 . -* -* 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 . -* -* Version: $Id: detours.cpp 248 2008-08-27 00:56:22Z pred $ -*/ - #include "detours.h" -#include +#include ISourcePawnEngine *CDetourManager::spengine = NULL; IGameConfig *CDetourManager::gameconf = NULL; -// Push 64-bit value onto the stack using two instructions. -// -// Pushing 0xF00DF00DF00DF00D: -// push 0xF00DF00D -// mov [rsp+4], 0xF00DF00D -static inline void X64_Push_Imm64(JitWriter *jit, jit_int64_t val) -{ - jit->write_ubyte(IA32_PUSH_IMM32); - jit->write_int32(jit_int32_t(val)); - if ((val >> 32) != 0) - IA32_Mov_ESP_Disp8_Imm32(jit, 4, (val >> 32)); -} - -// Jump to absolute 64-bit address using multiple instructions. -// -// Jumping to address 0xF00DF00DF00DF00D: -// push 0xF00DF00D -// mov [rsp+4], 0xF00DF00D -// ret -static inline void X64_Jump_Abs(JitWriter *jit, void *dest) -{ - X64_Push_Imm64(jit, jit_int64_t(dest)); - IA32_Return(jit); -} - -static inline void RelativeJump32(JitWriter *jit, void *target) -{ - jitoffs_t call = IA32_Jump_Imm32(jit, 0); - IA32_Write_Jump32_Abs(jit, call, target); -} - -#if defined(_WIN64) || defined(__x86_64__) -static inline bool IsShortJump(JitWriter *jit, void *target) -{ - int64_t diff = int64_t(target) - (int64_t(jit->outbase) + jit->get_outputpos() + OP_JMP_SIZE); - int32_t upperBits = (diff >> 32); - return upperBits == 0 || upperBits == -1; -} -#endif - -static inline void AbsJump(JitWriter *jit, void *target) -{ -#if defined(_WIN64) || defined(__x86_64__) - if (IsShortJump(jit, target)) - RelativeJump32(jit, target); - else - X64_Jump_Abs(jit, target); -#else - RelativeJump32(jit, target); -#endif -} - void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf) { CDetourManager::spengine = spengine; @@ -95,196 +12,101 @@ void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf) CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame) { - CDetour *detour = new CDetour(callbackfunction, trampoline, signame); - if (detour) + void* pAddress; + if (!gameconf->GetMemSig(signame, &pAddress)) { - if (!detour->Init(spengine, gameconf)) - { - delete detour; - return NULL; - } - - return detour; + g_pSM->LogError(myself, "Signature for %s not found in gamedata", signame); + return NULL; } - return NULL; -} - -CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, void *pAddress) -{ - CDetour *detour = new CDetour(callbackfunction, trampoline, pAddress); - if (detour) + if (!pAddress) { - if (!detour->Init(spengine, gameconf)) - { - delete detour; - return NULL; - } - - return detour; + g_pSM->LogError(myself, "Sigscan for %s failed", signame); + return NULL; } - return NULL; -} - -CDetour::CDetour(void *callbackfunction, void **trampoline, const char *signame) -{ - enabled = false; - detoured = false; - detour_address = NULL; - detour_trampoline = NULL; - this->signame = signame; - this->detour_callback = callbackfunction; - spengine = NULL; - gameconf = NULL; - this->trampoline = trampoline; -} - -CDetour::CDetour(void*callbackfunction, void **trampoline, void *pAddress) -{ - enabled = false; - detoured = false; - detour_address = pAddress; - detour_trampoline = NULL; - this->signame = NULL; - this->detour_callback = callbackfunction; - spengine = NULL; - gameconf = NULL; - this->trampoline = trampoline; + return CreateDetour(callbackfunction, trampoline, pAddress); } -bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf) +CDetour *CDetourManager::CreateDetour(void *callbackFunction, void **trampoline, void *pAddress) { - this->spengine = spengine; - this->gameconf = gameconf; + CDetour* detour = new CDetour(callbackFunction, trampoline, pAddress); - if (!CreateDetour()) + auto result = safetyhook::InlineHook::create(pAddress, callbackFunction, safetyhook::InlineHook::Flags::StartDisabled); + if(result) { - enabled = false; - return enabled; + detour->m_hook = std::move(result.value()); + *trampoline = detour->m_hook.original(); } - - enabled = true; - - return enabled; -} - -void CDetour::Destroy() -{ - DeleteDetour(); - delete this; -} - -bool CDetour::IsEnabled() -{ - return enabled; -} - -bool CDetour::CreateDetour() -{ - if (signame) + else { - if (!gameconf->GetMemSig(signame, &detour_address)) + auto err = result.error(); + switch(err.type) { - g_pSM->LogError(myself, "Signature for %s not found in gamedata", signame); - return false; + case safetyhook::InlineHook::Error::BAD_ALLOCATION: + if(err.allocator_error == safetyhook::Allocator::Error::BAD_VIRTUAL_ALLOC) + { + g_pSM->LogError(myself, "BAD_VIRTUAL_ALLOC hook %p", pAddress); + } + else if(err.allocator_error == safetyhook::Allocator::Error::NO_MEMORY_IN_RANGE) + { + g_pSM->LogError(myself, "NO_MEMORY_IN_RANGE hook %p", pAddress); + } + else + { + g_pSM->LogError(myself, "BAD_ALLOCATION hook %p errnum %i", pAddress, err.allocator_error); + } + break; + case safetyhook::InlineHook::Error::FAILED_TO_DECODE_INSTRUCTION: + g_pSM->LogError(myself, "FAILED_TO_DECODE_INSTRUCTION hook %p ip %p", pAddress, err.ip); + break; + case safetyhook::InlineHook::Error::SHORT_JUMP_IN_TRAMPOLINE: + g_pSM->LogError(myself, "SHORT_JUMP_IN_TRAMPOLINE hook %p ip %p", pAddress, err.ip); + break; + case safetyhook::InlineHook::Error::IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE: + g_pSM->LogError(myself, "IP_RELATIVE_INSTRUCTION_OUT_OF_RANGE hook %p ip %p", pAddress, err.ip); + break; + case safetyhook::InlineHook::Error::UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE: + g_pSM->LogError(myself, "UNSUPPORTED_INSTRUCTION_IN_TRAMPOLINE hook %p ip %p", pAddress, err.ip); + break; + case safetyhook::InlineHook::Error::FAILED_TO_UNPROTECT: + g_pSM->LogError(myself, "FAILED_TO_UNPROTECT hook %p ip %p", pAddress, err.ip); + break; + case safetyhook::InlineHook::Error::NOT_ENOUGH_SPACE: + g_pSM->LogError(myself, "NOT_ENOUGH_SPACE hook %p ip %p", pAddress, err.ip); + break; + default: + g_pSM->LogError(myself, "Unknown error %i hook %p ip %p", err.type, pAddress, err.ip); + break; } - - if (!detour_address) - { - g_pSM->LogError(myself, "Sigscan for %s failed", signame); - return false; - } - } - else if (!detour_address) - { - g_pSM->LogError(myself, "Invalid function address passed for detour"); - return false; - } - -#if defined(_WIN64) || defined(__x86_64__) - int shortBytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE); - detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, X64_ABS_SIZE); -#else - detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE); -#endif - - JitWriter wr; - JitWriter *jit = ≀ - jit_uint32_t CodeSize = 0; - - wr.outbase = NULL; - wr.outptr = NULL; - -jit_rewind: - - /* Patch old bytes in */ - if (wr.outbase != NULL) - { -#if defined(_WIN64) || defined(__x86_64__) - wr.outptr += shortBytes; - bool isShort = IsShortJump(jit, detour_address); - wr.outptr -= shortBytes; - if (isShort) - detour_restore.bytes = shortBytes; -#endif - /* Save restore bits */ - memcpy(detour_restore.patch, detour_address, detour_restore.bytes); - - copy_bytes((unsigned char *)detour_address, (unsigned char*)wr.outptr, detour_restore.bytes); - } - wr.outptr += detour_restore.bytes; - - /* Return to the original function */ - AbsJump(jit, (unsigned char *)detour_address + detour_restore.bytes); - - if (wr.outbase == NULL) - { - CodeSize = wr.get_outputpos(); - wr.outbase = (jitcode_t)spengine->AllocatePageMemory(CodeSize); - spengine->SetReadWrite(wr.outbase); - wr.outptr = wr.outbase; - detour_trampoline = wr.outbase; - goto jit_rewind; + + delete detour; + return NULL; } - spengine->SetReadExecute(wr.outbase); - - *trampoline = detour_trampoline; - - return true; + return detour; } -void CDetour::DeleteDetour() +CDetour::CDetour(void* callbackFunction, void **trampoline, void *pAddress) { - if (detoured) - { - DisableDetour(); - } +} - if (detour_trampoline) - { - /* Free the allocated trampoline memory */ - spengine->FreePageMemory(detour_trampoline); - detour_trampoline = NULL; - } +bool CDetour::IsEnabled() +{ + return m_hook.enabled(); } void CDetour::EnableDetour() { - if (!detoured) - { - DoGatePatch((unsigned char *)detour_address, detour_callback); - detoured = true; - } + m_hook.enable(); } void CDetour::DisableDetour() { - if (detoured) - { - /* Remove the patch */ - ApplyPatch(detour_address, 0, &detour_restore, NULL); - detoured = false; - } + m_hook.disable(); } + +void CDetour::Destroy() +{ + delete this; +} \ No newline at end of file diff --git a/public/CDetour/detours.h b/public/CDetour/detours.h index d8d1d24f72..43e16e245b 100644 --- a/public/CDetour/detours.h +++ b/public/CDetour/detours.h @@ -32,18 +32,8 @@ #ifndef _INCLUDE_SOURCEMOD_DETOURS_H_ #define _INCLUDE_SOURCEMOD_DETOURS_H_ -#include "extension.h" -#include -#include -#include "detourhelpers.h" - -/** - * CDetours class for SourceMod Extensions by pRED* - * detourhelpers.h entirely stolen from CSS:DM and were written by BAILOPAN (I assume). - * asm.h/c from devmaster.net (thanks cybermind) edited by pRED* to handle gcc -fPIC thunks correctly - * Concept by Nephyrin Zey (http://www.doublezen.net/) and Windows Detour Library (http://research.microsoft.com/sn/detours/) - * Member function pointer ideas by Don Clugston (http://www.codeproject.com/cpp/FastDelegate.asp) - */ +#include "safetyhook.hpp" +#include #define DETOUR_MEMBER_CALL(name) (this->*name##_Actual) #define DETOUR_STATIC_CALL(name) (name##_Actual) @@ -220,32 +210,9 @@ class CDetour friend class CDetourManager; protected: - CDetour(void *callbackfunction, void **trampoline, const char *signame); CDetour(void*callbackfunction, void **trampoline, void *pAddress); - - bool Init(ISourcePawnEngine *spengine, IGameConfig *gameconf); private: - - /* These create/delete the allocated memory */ - bool CreateDetour(); - void DeleteDetour(); - - bool enabled; - bool detoured; - - patch_t detour_restore; - /* Address of the detoured function */ - void *detour_address; - /* Address of the allocated trampoline function */ - void *detour_trampoline; - /* Address of the callback handler */ - void *detour_callback; - /* The function pointer used to call our trampoline */ - void **trampoline; - - const char *signame; - ISourcePawnEngine *spengine; - IGameConfig *gameconf; + SafetyHookInline m_hook{}; }; class CDetourManager @@ -293,10 +260,9 @@ class CDetourManager * * Note we changed the netadr_s reference into a void* to avoid needing to define the type */ - static CDetour *CreateDetour(void *callbackfunction, void **trampoline, const char *signame); - static CDetour *CreateDetour(void *callbackfunction, void **trampoline, void *pAddress); + static CDetour *CreateDetour(void *callbackFunction, void **trampoline, const char *signame); + static CDetour *CreateDetour(void *callbackFunction, void **trampoline, void *pAddress); - friend class CBlocker; friend class CDetour; private: @@ -304,4 +270,4 @@ class CDetourManager static IGameConfig *gameconf; }; -#endif // _INCLUDE_SOURCEMOD_DETOURS_H_ +#endif // _INCLUDE_SOURCEMOD_DETOURS_H_ \ No newline at end of file diff --git a/public/IGameHelpers.h b/public/IGameHelpers.h index b05c98d403..bc2ae12462 100644 --- a/public/IGameHelpers.h +++ b/public/IGameHelpers.h @@ -40,7 +40,7 @@ */ #define SMINTERFACE_GAMEHELPERS_NAME "IGameHelpers" -#define SMINTERFACE_GAMEHELPERS_VERSION 11 +#define SMINTERFACE_GAMEHELPERS_VERSION 12 class CBaseEntity; class CBaseHandle; @@ -351,6 +351,13 @@ namespace SourceMod * @return 64-bit server Steam id. */ virtual uint64_t GetServerSteamId64() const =0; + + /** + * @brief Finds a given entity's server class. + * + * @return ServerClass pointer on success, nullptr on failure. + */ + virtual ServerClass *FindEntityServerClass(CBaseEntity *pEntity) = 0; }; } diff --git a/public/safetyhook b/public/safetyhook new file mode 160000 index 0000000000..4c93319578 --- /dev/null +++ b/public/safetyhook @@ -0,0 +1 @@ +Subproject commit 4c933195789e9a0551a49c929dc3a2dd1e8fb97f diff --git a/pushbuild.txt b/pushbuild.txt index 356be3572b..13d479bdbe 100644 --- a/pushbuild.txt +++ b/pushbuild.txt @@ -1,6 +1,6 @@ a billion and nanas joys of buildbot, part 2: buildböt and the very lonely square-shaped duck -joys of buildbot, part 3: an accidental event proves troublesome for a psychic fish +joys of buildbot, part 3: an accidental event proves troublesome for a psychotic fish joys of buildbot, part 4: a transient mummy is perplexed by a broken wand buildbot has horrible bloogs I am the very model of a modern major general diff --git a/tools/buildbot/upload_symbols.py b/tools/buildbot/upload_symbols.py index 9756fdb5c4..757e22fb7b 100644 --- a/tools/buildbot/upload_symbols.py +++ b/tools/buildbot/upload_symbols.py @@ -1,4 +1,5 @@ # vim: ts=8 sts=2 sw=2 tw=99 et ft=python: +import shutil import sys import subprocess import os @@ -15,6 +16,9 @@ symbol_file = sys.argv[1] cmd_argv = sys.argv[2:] +# Find the dump_syms executable. (On Windows, subprocess.Popen doesn't use PATH unless shell=True.) +cmd_argv[0] = shutil.which(cmd_argv[0]) + sys.stdout.write(' '.join(cmd_argv)) sys.stdout.write('\n') @@ -100,15 +104,17 @@ def runCommand(argv): index = 1 while lines[index].split(None, 1)[0] == 'INFO': - index += 1; + index += 1 for root, info in roots.items(): lines.insert(index, 'INFO REPO ' + ' '.join([info[1], info[0], root])) - index += 1; + index += 1 out = os.linesep.join(lines).encode('utf8') request = urllib.Request(SYMBOL_SERVER, out) request.add_header('Content-Type', 'text/plain') +if 'BREAKPAD_SYMBOL_SERVER_TOKEN' in os.environ: + request.add_header('X-Auth', os.environ['BREAKPAD_SYMBOL_SERVER_TOKEN']) server_response = urllib.urlopen(request).read().decode('utf8').strip() print(server_response) diff --git a/tools/checkout-deps.sh b/tools/checkout-deps.sh index 059bd1776d..961a627924 100755 --- a/tools/checkout-deps.sh +++ b/tools/checkout-deps.sh @@ -45,9 +45,9 @@ getmysql () { if [ ! -d $mysqlfolder ]; then if [ `command -v wget` ]; then - wget $mysqlurl -O $mysqlfolder.$archive_ext + wget -q $mysqlurl -O $mysqlfolder.$archive_ext elif [ `command -v curl` ]; then - curl -o $mysqlfolder.$archive_ext $mysqlurl + curl -sS -o $mysqlfolder.$archive_ext $mysqlurl else echo "Failed to locate wget or curl. Install one of these programs to download MySQL." exit 1 @@ -144,8 +144,13 @@ else cd .. fi +want_mock_sdk=0 for sdk in "${sdks[@]}" do + if [ "$sdk" == "mock" ]; then + want_mock_sdk=1 + continue + fi repo=hl2sdk-proxy-repo origin="https://github.com/alliedmodders/hl2sdk" name=hl2sdk-$sdk @@ -153,11 +158,13 @@ do checkout done -name=hl2sdk-mock -branch=master -repo="https://github.com/alliedmodders/hl2sdk-mock" -origin= -checkout +if [ $want_mock_sdk -eq 1 ]; then + name=hl2sdk-mock + branch=master + repo="https://github.com/alliedmodders/hl2sdk-mock" + origin= + checkout +fi python_cmd=`command -v python3` if [ -z "$python_cmd" ]; then @@ -203,7 +210,11 @@ if [ $? -eq 1 ]; then name=ambuild checkout - if [ $iswin -eq 1 ] || [ $ismac -eq 1 ]; then + if [ $iswin -eq 1 ]; then + # Without first doing this explicitly, ambuild install fails on newer Python versions on Windows + $python_cmd -m pip install wheel + $python_cmd -m pip install ./ambuild + elif [ $ismac -eq 1 ]; then $python_cmd -m pip install ./ambuild else echo "Installing AMBuild at the user level. Location can be: ~/.local/bin" diff --git a/translations/vi/adminhelp.phrases.txt b/translations/vi/adminhelp.phrases.txt index e6bb77f43f..417748d100 100644 --- a/translations/vi/adminhelp.phrases.txt +++ b/translations/vi/adminhelp.phrases.txt @@ -17,7 +17,7 @@ "Type sm_help to see more" { - "vi" "Gõ sm_help để xem thêm câu lệnh" + "vi" "Gõ sm_help {1} để xem thêm câu lệnh" } "Entries n - m in page k" diff --git a/translations/vi/basetriggers.phrases.txt b/translations/vi/basetriggers.phrases.txt index fb5efac1ed..e17a01490c 100644 --- a/translations/vi/basetriggers.phrases.txt +++ b/translations/vi/basetriggers.phrases.txt @@ -20,6 +20,11 @@ "vi" "Hỏa lực thân thiện bị vô hiệu hóa." } + "Friendly Fire Percent" + { + "vi" "Phe ta bắn đồng đội chiếm {1}%." + } + "Current Map" { "vi" "Bản đồ hiện tại là {1}." diff --git a/translations/vi/nominations.phrases.txt b/translations/vi/nominations.phrases.txt index 85cfa7ecfa..124985b866 100644 --- a/translations/vi/nominations.phrases.txt +++ b/translations/vi/nominations.phrases.txt @@ -65,4 +65,9 @@ "vi" "Đã đề cử" } + "Map Not In Pool" + { + "vi" "Bản đồ '{1}' không nằm trong danh sách đề cử." + } + }