From a75ff4f9b64b2456b834f0bda5ab0a1ef0418c9a Mon Sep 17 00:00:00 2001
From: bottiger1 <55270538+bottiger1@users.noreply.github.com>
Date: Tue, 7 May 2024 14:23:41 -0700
Subject: [PATCH 1/3] update for 64 bits
---
AMBuildScript | 13 +-
Extension/AMBuilder | 21 +-
Extension/CDetour/detourhelpers.h | 100 -------
Extension/CDetour/detours.cpp | 228 ----------------
Extension/CDetour/detours.h | 249 ------------------
Extension/asm/asm.c | 418 ------------------------------
Extension/asm/asm.h | 40 ---
Extension/gsnatives.cpp | 2 +-
Extension/swgsdetours.cpp | 2 +
Extension/swgsdetours.h | 3 +-
Extension/swhttp.h | 4 +-
Extension/swhttprequest.h | 2 +-
build/build | 11 +
build/clean | 4 +
14 files changed, 47 insertions(+), 1050 deletions(-)
delete mode 100644 Extension/CDetour/detourhelpers.h
delete mode 100644 Extension/CDetour/detours.cpp
delete mode 100644 Extension/CDetour/detours.h
delete mode 100644 Extension/asm/asm.c
delete mode 100644 Extension/asm/asm.h
create mode 100755 build/build
create mode 100755 build/clean
diff --git a/AMBuildScript b/AMBuildScript
index db084e2f..160976e9 100644
--- a/AMBuildScript
+++ b/AMBuildScript
@@ -147,17 +147,17 @@ class SteamWorksConfig(object):
'-pipe',
'-fno-strict-aliasing',
'-Wall',
- '-Werror',
+ #'-Werror',
'-Wno-unused',
'-Wno-switch',
'-Wno-format',
'-Wno-format-security',
'-Wno-array-bounds',
'-msse',
- '-m32',
+ '-fPIC',
]
cxx.cxxflags += [
- '-std=c++11',
+ '-std=c++17',
]
have_gcc = cxx.vendor == 'gcc'
@@ -179,7 +179,6 @@ class SteamWorksConfig(object):
cxx.cxxflags += ['-Wno-deprecated']
cxx.cflags += ['-Wno-sometimes-uninitialized']
- cxx.linkflags += ['-m32']
cxx.cxxflags += [
'-fno-exceptions',
'-fno-threadsafe-statics',
@@ -269,12 +268,14 @@ class SteamWorksConfig(object):
cxx.defines += ['WIN32', '_WINDOWS']
def ConfigureForExtension(self, context, compiler):
- compiler.cxxincludes += [
+ compiler.includes += [
os.path.join(context.currentSourcePath),
os.path.join(context.currentSourcePath, 'sdk'),
os.path.join(self.sm_root, 'public'),
os.path.join(self.sm_root, 'public', 'extensions'),
- os.path.join(self.sm_root, 'public', 'sourcepawn'),
+ os.path.join(self.sm_root, 'sourcepawn', 'include'),
+ os.path.join(self.sm_root, 'public', 'amtl'),
+ os.path.join(self.sm_root, 'public', 'amtl', 'amtl'),
]
return compiler
diff --git a/Extension/AMBuilder b/Extension/AMBuilder
index 64d57e02..71aa9b96 100644
--- a/Extension/AMBuilder
+++ b/Extension/AMBuilder
@@ -16,8 +16,15 @@ project.sources += [
'swhttprequest.cpp',
'swgchooks.cpp',
'sdk/smsdk_ext.cpp',
- 'CDetour/detours.cpp',
- 'asm/asm.c'
+
+ os.path.join(SteamWorks.sm_root, 'public', 'CDetour', 'detours.cpp'),
+ os.path.join(SteamWorks.sm_root, 'public', 'asm', 'asm.c'),
+ os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'decode.c'),
+ os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'itab.c'),
+ os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'syn-att.c'),
+ os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'syn-intel.c'),
+ os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'syn.c'),
+ os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'udis86.c'),
]
for sdk_name in SteamWorks.sdks:
@@ -29,10 +36,16 @@ for sdk_name in SteamWorks.sdks:
binary.compiler.cxxincludes += [os.path.join(SteamWorks.steamworks_root, 'public', 'steam'), os.path.join(sdk.path, 'public', 'steam')];
if binary.compiler.target.platform == 'linux':
- binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'linux32', 'libsteam_api.so'),;
+ if binary.compiler.target.arch == 'x86_64':
+ binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'linux64', 'libsteam_api.so'),;
+ else:
+ binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'linux32', 'libsteam_api.so'),;
if binary.compiler.target.platform == 'windows':
- binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'steam_api.lib'),;
+ if binary.compiler.target.arch == 'x86_64':
+ binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'win64', 'steam_api64.lib'),;
+ else:
+ binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'steam_api.lib'),;
if binary.compiler.target.platform == 'mac':
binary.compiler.postlink += os.path.join(SteamWorks.steamworks_root, 'redistributable_bin', 'osx', 'libsteam_api.dylib'),;
diff --git a/Extension/CDetour/detourhelpers.h b/Extension/CDetour/detourhelpers.h
deleted file mode 100644
index cff73cc7..00000000
--- a/Extension/CDetour/detourhelpers.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/**
- * vim: set ts=4 :
- * =============================================================================
- * SourceMod
- * Copyright (C) 2004-2007 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: detourhelpers.h 248 2008-08-27 00:56:22Z pred $
- */
-
-#ifndef _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
-#define _INCLUDE_SOURCEMOD_DETOURHELPERS_H_
-
-#if defined PLATFORM_POSIX
-#include
-#ifndef PAGE_SIZE
-#define PAGE_SIZE 4096
-#endif
-#define ALIGN(ar) ((long)ar & ~(PAGE_SIZE-1))
-#define PAGE_EXECUTE_READWRITE PROT_READ|PROT_WRITE|PROT_EXEC
-#endif
-
-struct patch_t
-{
- patch_t()
- {
- patch[0] = 0;
- bytes = 0;
- }
- unsigned char patch[20];
- size_t bytes;
-};
-
-inline void ProtectMemory(void *addr, int length, int prot)
-{
-#if defined PLATFORM_POSIX
- void *addr2 = (void *)ALIGN(addr);
- mprotect(addr2, sysconf(_SC_PAGESIZE), prot);
-#elif defined PLATFORM_WINDOWS
- DWORD old_prot;
- VirtualProtect(addr, length, prot, &old_prot);
-#endif
-}
-
-inline void SetMemPatchable(void *address, size_t size)
-{
- ProtectMemory(address, (int)size, PAGE_EXECUTE_READWRITE);
-}
-
-inline void DoGatePatch(unsigned char *target, void *callback)
-{
- SetMemPatchable(target, 20);
-
- target[0] = 0xFF; /* JMP */
- target[1] = 0x25; /* MEM32 */
- *(void **)(&target[2]) = callback;
-}
-
-inline void ApplyPatch(void *address, int offset, const patch_t *patch, patch_t *restore)
-{
- ProtectMemory(address, 20, PAGE_EXECUTE_READWRITE);
-
- unsigned char *addr = (unsigned char *)address + offset;
- if (restore)
- {
- for (size_t i=0; ibytes; i++)
- {
- restore->patch[i] = addr[i];
- }
- restore->bytes = patch->bytes;
- }
-
- for (size_t i=0; ibytes; i++)
- {
- addr[i] = patch->patch[i];
- }
-}
-
-#endif //_INCLUDE_SOURCEMOD_DETOURHELPERS_H_
diff --git a/Extension/CDetour/detours.cpp b/Extension/CDetour/detours.cpp
deleted file mode 100644
index 9e304149..00000000
--- a/Extension/CDetour/detours.cpp
+++ /dev/null
@@ -1,228 +0,0 @@
-/**
-* vim: set ts=4 :
-* =============================================================================
-* SourceMod
-* Copyright (C) 2004-2008 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
-
-ISourcePawnEngine *CDetourManager::spengine = NULL;
-IGameConfig *CDetourManager::gameconf = NULL;
-
-void CDetourManager::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
-{
- CDetourManager::spengine = spengine;
- CDetourManager::gameconf = gameconf;
-}
-
-CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, const char *signame)
-{
- CDetour *detour = new CDetour(callbackfunction, trampoline, signame);
- if (detour)
- {
- if (!detour->Init(spengine, gameconf))
- {
- delete detour;
- return NULL;
- }
-
- return detour;
- }
-
- return NULL;
-}
-
-CDetour *CDetourManager::CreateDetour(void *callbackfunction, void **trampoline, void *address)
-{
- CDetour *detour = new CDetour(callbackfunction, trampoline, address);
- if (detour)
- {
- if (!detour->Init(spengine, gameconf))
- {
- delete detour;
- return NULL;
- }
-
- return detour;
- }
-
- 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->address = NULL;
- 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 = NULL;
- detour_trampoline = NULL;
- this->signame = NULL;
- this->address = pAddress;
- this->detour_callback = callbackfunction;
- spengine = NULL;
- gameconf = NULL;
- this->trampoline = trampoline;
-}
-
-bool CDetour::Init(ISourcePawnEngine *spengine, IGameConfig *gameconf)
-{
- this->spengine = spengine;
- this->gameconf = gameconf;
-
- if (!CreateDetour())
- {
- enabled = false;
- return enabled;
- }
-
- enabled = true;
-
- return enabled;
-}
-
-void CDetour::Destroy()
-{
- DeleteDetour();
- delete this;
-}
-
-bool CDetour::IsEnabled()
-{
- return enabled;
-}
-
-bool CDetour::CreateDetour()
-{
- if (signame != NULL && !gameconf->GetMemSig(signame, &detour_address))
- {
- g_pSM->LogError(myself, "Could not locate %s - Disabling detour", signame);
- return false;
- }
- else if (address != NULL)
- {
- detour_address = address;
- }
-
- if (!detour_address)
- {
- g_pSM->LogError(myself, "Sigscan for %s failed - Disabling detour to prevent crashes", signame);
- return false;
- }
-
- detour_restore.bytes = copy_bytes((unsigned char *)detour_address, NULL, OP_JMP_SIZE+1);
-
- /* First, save restore bits */
- for (size_t i=0; iAllocatePageMemory(CodeSize);
- spengine->SetReadWrite(wr.outbase);
- wr.outptr = wr.outbase;
- detour_trampoline = wr.outbase;
- goto jit_rewind;
- }
-
- spengine->SetReadExecute(wr.outbase);
-
- *trampoline = detour_trampoline;
-
- return true;
-}
-
-void CDetour::DeleteDetour()
-{
- if (detoured)
- {
- DisableDetour();
- }
-
- if (detour_trampoline)
- {
- /* Free the allocated trampoline memory */
- spengine->FreePageMemory(detour_trampoline);
- detour_trampoline = NULL;
- }
-}
-
-void CDetour::EnableDetour()
-{
- if (!detoured)
- {
- DoGatePatch((unsigned char *)detour_address, &detour_callback);
- detoured = true;
- }
-}
-
-void CDetour::DisableDetour()
-{
- if (detoured)
- {
- /* Remove the patch */
- ApplyPatch(detour_address, 0, &detour_restore, NULL);
- detoured = false;
- }
-}
diff --git a/Extension/CDetour/detours.h b/Extension/CDetour/detours.h
deleted file mode 100644
index c68d299b..00000000
--- a/Extension/CDetour/detours.h
+++ /dev/null
@@ -1,249 +0,0 @@
-/**
-* vim: set ts=4 :
-* =============================================================================
-* SourceMod
-* Copyright (C) 2004-2008 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.h 257 2008-09-23 03:12:13Z pred $
-*/
-
-#ifndef _INCLUDE_SOURCEMOD_DETOURS_H_
-#define _INCLUDE_SOURCEMOD_DETOURS_H_
-
-#include "smsdk_ext.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)
- */
-
-#define DETOUR_MEMBER_CALL(name) (this->*name##_Actual)
-#define DETOUR_STATIC_CALL(name) (name##_Actual)
-
-#define DETOUR_DECL_STATIC0(name, ret) \
-ret (*name##_Actual)(void) = NULL; \
-ret name(void)
-
-#define DETOUR_DECL_STATIC1(name, ret, p1type, p1name) \
-ret (*name##_Actual)(p1type) = NULL; \
-ret name(p1type p1name)
-
-#define DETOUR_DECL_STATIC4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
-ret (*name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
-ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
-
-#define DETOUR_DECL_STATIC6(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name, p5type, p5name, p6type, p6name) \
-ret (*name##_Actual)(p1type, p2type, p3type, p4type, p5type, p6type) = NULL; \
-ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name, p5type p5name, p6type p6name)
-
-#define DETOUR_DECL_MEMBER0(name, ret) \
-class name##Class \
-{ \
-public: \
- ret name(); \
- static ret (name##Class::* name##_Actual)(void); \
-}; \
-ret (name##Class::* name##Class::name##_Actual)(void) = NULL; \
-ret name##Class::name()
-
-#define DETOUR_DECL_MEMBER1(name, ret, p1type, p1name) \
-class name##Class \
-{ \
-public: \
- ret name(p1type p1name); \
- static ret (name##Class::* name##_Actual)(p1type); \
-}; \
-ret (name##Class::* name##Class::name##_Actual)(p1type) = NULL; \
-ret name##Class::name(p1type p1name)
-
-#define DETOUR_DECL_MEMBER2(name, ret, p1type, p1name, p2type, p2name) \
-class name##Class \
-{ \
-public: \
- ret name(p1type p1name, p2type p2name); \
- static ret (name##Class::* name##_Actual)(p1type, p2type); \
-}; \
-ret (name##Class::* name##Class::name##_Actual)(p1type, p2type) = NULL; \
-ret name##Class::name(p1type p1name, p2type p2name)
-
-#define DETOUR_DECL_MEMBER3(name, ret, p1type, p1name, p2type, p2name, p3type, p3name) \
-class name##Class \
-{ \
-public: \
- ret name(p1type p1name, p2type p2name, p3type p3name); \
- static ret (name##Class::* name##_Actual)(p1type, p2type, p3type); \
-}; \
-ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type) = NULL; \
-ret name##Class::name(p1type p1name, p2type p2name, p3type p3name)
-
-#define DETOUR_DECL_MEMBER4(name, ret, p1type, p1name, p2type, p2name, p3type, p3name, p4type, p4name) \
-class name##Class \
-{ \
-public: \
- ret name(p1type p1name, p2type p2name, p3type p3name, p4type p4name); \
- static ret (name##Class::* name##_Actual)(p1type, p2type, p3type, p4type); \
-}; \
-ret (name##Class::* name##Class::name##_Actual)(p1type, p2type, p3type, p4type) = NULL; \
-ret name##Class::name(p1type p1name, p2type p2name, p3type p3name, p4type p4name)
-
-
-#define GET_MEMBER_CALLBACK(name) (void *)GetCodeAddress(&name##Class::name)
-#define GET_MEMBER_TRAMPOLINE(name) (void **)(&name##Class::name##_Actual)
-
-#define GET_STATIC_CALLBACK(name) (void *)&name
-#define GET_STATIC_TRAMPOLINE(name) (void **)&name##_Actual
-
-#define DETOUR_CREATE_MEMBER(name, gamedata) CDetourManager::CreateDetour(GET_MEMBER_CALLBACK(name), GET_MEMBER_TRAMPOLINE(name), gamedata);
-#define DETOUR_CREATE_STATIC(name, gamedata) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), gamedata);
-#define DETOUR_CREATE_STATIC_FIXED(name, address) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), address);
-
-
-class GenericClass {};
-typedef void (GenericClass::*VoidFunc)();
-
-inline void *GetCodeAddr(VoidFunc mfp)
-{
- return *(void **)&mfp;
-}
-
-/**
- * Converts a member function pointer to a void pointer.
- * This relies on the assumption that the code address lies at mfp+0
- * This is the case for both g++ and later MSVC versions on non virtual functions but may be different for other compilers
- * Based on research by Don Clugston : http://www.codeproject.com/cpp/FastDelegate.asp
- */
-#define GetCodeAddress(mfp) GetCodeAddr(reinterpret_cast(mfp))
-
-class CDetourManager;
-
-class CDetour
-{
-public:
-
- bool IsEnabled();
-
- /**
- * These would be somewhat self-explanatory I hope
- */
- void EnableDetour();
- void DisableDetour();
-
- void Destroy();
-
- friend class CDetourManager;
-
-protected:
- CDetour(void *callbackfunction, void **trampoline, const char *signame);
- CDetour(void *callbackfunction, void **trampoline, void *address);
-
- 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;
- void *address;
- ISourcePawnEngine *spengine;
- IGameConfig *gameconf;
-};
-
-class CDetourManager
-{
-public:
-
- static void Init(ISourcePawnEngine *spengine, IGameConfig *gameconf);
-
- /**
- * Creates a new detour
- *
- * @param callbackfunction Void pointer to your detour callback function.
- * @param trampoline Address of the trampoline pointer
- * @param signame Section name containing a signature to fetch from the gamedata file.
- * @return A new CDetour pointer to control your detour.
- *
- * Example:
- *
- * CBaseServer::ConnectClient(netadr_s &, int, int, int, char const*, char const*, char const*, int)
- *
- * Define a new class with the required function and a member function pointer to the same type:
- *
- * class CBaseServerDetour
- * {
- * public:
- * bool ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
- * static bool (CBaseServerDetour::* ConnectClient_Actual)(void *netaddr_s, int, int, int, char const*, char const*, char const*, int);
- * }
- *
- * void *callbackfunc = GetCodeAddress(&CBaseServerDetour::ConnectClient);
- * void **trampoline = (void **)(&CBaseServerDetour::ConnectClient_Actual);
- *
- * Creation:
- * CDetourManager::CreateDetour(callbackfunc, trampoline, "ConnectClient");
- *
- * Usage:
- *
- * CBaseServerDetour::ConnectClient(void *netaddr_s, int, int, int, char const*, char const*, char const*, int)
- * {
- * //pre hook code
- * bool result = (this->*ConnectClient_Actual)(netaddr_s, rest of params);
- * //post hook code
- * return result;
- * }
- *
- * 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 *address);
-
- friend class CBlocker;
- friend class CDetour;
-
-private:
- static ISourcePawnEngine *spengine;
- static IGameConfig *gameconf;
-};
-
-#endif // _INCLUDE_SOURCEMOD_DETOURS_H_
diff --git a/Extension/asm/asm.c b/Extension/asm/asm.c
deleted file mode 100644
index 7e92d23d..00000000
--- a/Extension/asm/asm.c
+++ /dev/null
@@ -1,418 +0,0 @@
-#include "asm.h"
-
-#ifndef WIN32
-#define _GNU_SOURCE
-#include
-#include
-
-#define REG_EAX 0
-#define REG_ECX 1
-#define REG_EDX 2
-#define REG_EBX 3
-
-#define IA32_MOV_REG_IMM 0xB8 // encoding is +r
-#endif
-
-/**
-* Checks if a call to a fpic thunk has just been written into dest.
-* If found replaces it with a direct mov that sets the required register to the value of pc.
-*
-* @param dest Destination buffer where a call opcode + addr (5 bytes) has just been written.
-* @param pc The program counter value that needs to be set (usually the next address from the source).
-* @noreturn
-*/
-void check_thunks(unsigned char *dest, unsigned char *pc)
-{
-#if defined WIN32
- return;
-#else
- /* Step write address back 4 to the start of the function address */
- unsigned char *writeaddr = dest - 4;
- unsigned char *calloffset = *(unsigned char **)writeaddr;
- unsigned char *calladdr = (unsigned char *)(dest + (unsigned int)calloffset);
-
- /* Lookup name of function being called */
- if ((*calladdr == 0x8B) && (*(calladdr+2) == 0x24) && (*(calladdr+3) == 0xC3))
- {
- //a thunk maybe?
- char movByte = IA32_MOV_REG_IMM;
-
- /* Calculate the correct mov opcode */
- switch (*(calladdr+1))
- {
- case 0x04:
- {
- movByte += REG_EAX;
- break;
- }
- case 0x1C:
- {
- movByte += REG_EBX;
- break;
- }
- case 0x0C:
- {
- movByte += REG_ECX;
- break;
- }
- case 0x14:
- {
- movByte += REG_EDX;
- break;
- }
- default:
- {
- break;
- }
- }
-
- /* Move our write address back one to where the call opcode was */
- writeaddr--;
-
-
- /* Write our mov */
- *writeaddr = movByte;
- writeaddr++;
-
- /* Write the value - The provided program counter value */
- *(void **)writeaddr = (void *)pc;
- writeaddr += 4;
- }
-
- return;
-#endif
-}
-
-//if dest is NULL, returns minimum number of bytes needed to be copied
-//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
-//http://www.devmaster.net/forums/showthread.php?t=2311
-int copy_bytes(unsigned char *func, unsigned char* dest, int required_len) {
- int bytecount = 0;
-
- while(bytecount < required_len && *func != 0xCC)
- {
- // prefixes F0h, F2h, F3h, 66h, 67h, D8h-DFh, 2Eh, 36h, 3Eh, 26h, 64h and 65h
- int operandSize = 4;
- int FPU = 0;
- int twoByte = 0;
- unsigned char opcode = 0x90;
- unsigned char modRM = 0xFF;
- while(*func == 0xF0 ||
- *func == 0xF2 ||
- *func == 0xF3 ||
- (*func & 0xFC) == 0x64 ||
- (*func & 0xF8) == 0xD8 ||
- (*func & 0x7E) == 0x62)
- {
- if(*func == 0x66)
- {
- operandSize = 2;
- }
- else if((*func & 0xF8) == 0xD8)
- {
- FPU = *func;
- if (dest)
- *dest++ = *func++;
- else
- func++;
- bytecount++;
- break;
- }
-
- if (dest)
- *dest++ = *func++;
- else
- func++;
- bytecount++;
- }
-
- // two-byte opcode byte
- if(*func == 0x0F)
- {
- twoByte = 1;
- if (dest)
- *dest++ = *func++;
- else
- func++;
- bytecount++;
- }
-
- // opcode byte
- opcode = *func++;
- if (dest) *dest++ = opcode;
- bytecount++;
-
- // mod R/M byte
- modRM = 0xFF;
- if(FPU)
- {
- if((opcode & 0xC0) != 0xC0)
- {
- modRM = opcode;
- }
- }
- else if(!twoByte)
- {
- if((opcode & 0xC4) == 0x00 ||
- ((opcode & 0xF4) == 0x60 && ((opcode & 0x0A) == 0x02 || (opcode & 0x09) == 0x09)) ||
- (opcode & 0xF0) == 0x80 ||
- ((opcode & 0xF8) == 0xC0 && (opcode & 0x0E) != 0x02) ||
- (opcode & 0xFC) == 0xD0 ||
- (opcode & 0xF6) == 0xF6)
- {
- modRM = *func++;
- if (dest) *dest++ = modRM;
- bytecount++;
- }
- }
- else
- {
- if(((opcode & 0xF0) == 0x00 && (opcode & 0x0F) >= 0x04 && (opcode & 0x0D) != 0x0D) ||
- (opcode & 0xF0) == 0x30 ||
- opcode == 0x77 ||
- (opcode & 0xF0) == 0x80 ||
- ((opcode & 0xF0) == 0xA0 && (opcode & 0x07) <= 0x02) ||
- (opcode & 0xF8) == 0xC8)
- {
- // No mod R/M byte
- }
- else
- {
- modRM = *func++;
- if (dest) *dest++ = modRM;
- bytecount++;
- }
- }
-
- // SIB
- if((modRM & 0x07) == 0x04 &&
- (modRM & 0xC0) != 0xC0)
- {
- if (dest)
- *dest++ = *func++; //SIB
- else
- func++;
- bytecount++;
- }
-
- // mod R/M displacement
-
- // Dword displacement, no base
- if((modRM & 0xC5) == 0x05) {
- if (dest) {
- *(unsigned int*)dest = *(unsigned int*)func;
- dest += 4;
- }
- func += 4;
- bytecount += 4;
- }
-
- // Byte displacement
- if((modRM & 0xC0) == 0x40) {
- if (dest)
- *dest++ = *func++;
- else
- func++;
- bytecount++;
- }
-
- // Dword displacement
- if((modRM & 0xC0) == 0x80) {
- if (dest) {
- *(unsigned int*)dest = *(unsigned int*)func;
- dest += 4;
- }
- func += 4;
- bytecount += 4;
- }
-
- // immediate
- if(FPU)
- {
- // Can't have immediate operand
- }
- else if(!twoByte)
- {
- if((opcode & 0xC7) == 0x04 ||
- (opcode & 0xFE) == 0x6A || // PUSH/POP/IMUL
- (opcode & 0xF0) == 0x70 || // Jcc
- opcode == 0x80 ||
- opcode == 0x83 ||
- (opcode & 0xFD) == 0xA0 || // MOV
- opcode == 0xA8 || // TEST
- (opcode & 0xF8) == 0xB0 || // MOV
- (opcode & 0xFE) == 0xC0 || // RCL
- opcode == 0xC6 || // MOV
- opcode == 0xCD || // INT
- (opcode & 0xFE) == 0xD4 || // AAD/AAM
- (opcode & 0xF8) == 0xE0 || // LOOP/JCXZ
- opcode == 0xEB ||
- (opcode == 0xF6 && (modRM & 0x30) == 0x00)) // TEST
- {
- if (dest)
- *dest++ = *func++;
- else
- func++;
- bytecount++;
- }
- else if((opcode & 0xF7) == 0xC2) // RET
- {
- if (dest) {
- *(unsigned short*)dest = *(unsigned short*)func;
- dest += 2;
- }
- func += 2;
- bytecount += 2;
- }
- else if((opcode & 0xFC) == 0x80 ||
- (opcode & 0xC7) == 0x05 ||
- (opcode & 0xF8) == 0xB8 ||
- (opcode & 0xFE) == 0xE8 || // CALL/Jcc
- (opcode & 0xFE) == 0x68 ||
- (opcode & 0xFC) == 0xA0 ||
- (opcode & 0xEE) == 0xA8 ||
- opcode == 0xC7 ||
- (opcode == 0xF7 && (modRM & 0x30) == 0x00))
- {
- if (dest) {
- //Fix CALL/JMP offset
- if ((opcode & 0xFE) == 0xE8) {
- if (operandSize == 4)
- {
- *(long*)dest = ((func + *(long*)func) - dest);
-
- //pRED* edit. func is the current address of the call address, +4 is the next instruction, so the value of $pc
- check_thunks(dest+4, func+4);
- }
- else
- *(short*)dest = ((func + *(short*)func) - dest);
-
- } else {
- if (operandSize == 4)
- *(unsigned long*)dest = *(unsigned long*)func;
- else
- *(unsigned short*)dest = *(unsigned short*)func;
- }
- dest += operandSize;
- }
- func += operandSize;
- bytecount += operandSize;
-
- }
- }
- else
- {
- if(opcode == 0xBA || // BT
- opcode == 0x0F || // 3DNow!
- (opcode & 0xFC) == 0x70 || // PSLLW
- (opcode & 0xF7) == 0xA4 || // SHLD
- opcode == 0xC2 ||
- opcode == 0xC4 ||
- opcode == 0xC5 ||
- opcode == 0xC6)
- {
- if (dest)
- *dest++ = *func++;
- else
- func++;
- }
- else if((opcode & 0xF0) == 0x80) // Jcc -i
- {
- if (dest) {
- if (operandSize == 4)
- *(unsigned long*)dest = *(unsigned long*)func;
- else
- *(unsigned short*)dest = *(unsigned short*)func;
-
- dest += operandSize;
- }
- func += operandSize;
- bytecount += operandSize;
- }
- }
- }
-
- return bytecount;
-}
-
-//insert a specific JMP instruction at the given location
-void inject_jmp(void* src, void* dest) {
- *(unsigned char*)src = OP_JMP;
- *(long*)((unsigned char*)src+1) = (long)((unsigned char*)dest - ((unsigned char*)src + OP_JMP_SIZE));
-}
-
-//fill a given block with NOPs
-void fill_nop(void* src, unsigned int len) {
- unsigned char* src2 = (unsigned char*)src;
- while (len) {
- *src2++ = OP_NOP;
- --len;
- }
-}
-
-void* eval_jump(void* src) {
- unsigned char* addr = (unsigned char*)src;
-
- if (!addr) return 0;
-
- //import table jump
- if (addr[0] == OP_PREFIX && addr[1] == OP_JMP_SEG) {
- addr += 2;
- addr = *(unsigned char**)addr;
- //TODO: if addr points into the IAT
- return *(void**)addr;
- }
-
- //8bit offset
- else if (addr[0] == OP_JMP_BYTE) {
- addr = &addr[OP_JMP_BYTE_SIZE] + *(char*)&addr[1];
- //mangled 32bit jump?
- if (addr[0] == OP_JMP) {
- addr = addr + *(int*)&addr[1];
- }
- return addr;
- }
- /*
- //32bit offset
- else if (addr[0] == OP_JMP) {
- addr = &addr[OP_JMP_SIZE] + *(int*)&addr[1];
- }
- */
-
- return addr;
-}
-/*
-from ms detours package
-static bool detour_is_imported(PBYTE pbCode, PBYTE pbAddress)
-{
- MEMORY_BASIC_INFORMATION mbi;
- VirtualQuery((PVOID)pbCode, &mbi, sizeof(mbi));
- __try {
- PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)mbi.AllocationBase;
- if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
- return false;
- }
-
- PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)((PBYTE)pDosHeader +
- pDosHeader->e_lfanew);
- if (pNtHeader->Signature != IMAGE_NT_SIGNATURE) {
- return false;
- }
-
- if (pbAddress >= ((PBYTE)pDosHeader +
- pNtHeader->OptionalHeader
- .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress) &&
- pbAddress < ((PBYTE)pDosHeader +
- pNtHeader->OptionalHeader
- .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress +
- pNtHeader->OptionalHeader
- .DataDirectory[IMAGE_DIRECTORY_ENTRY_IAT].Size)) {
- return true;
- }
- return false;
- }
- __except(EXCEPTION_EXECUTE_HANDLER) {
- return false;
- }
-}
-*/
diff --git a/Extension/asm/asm.h b/Extension/asm/asm.h
deleted file mode 100644
index 838e6916..00000000
--- a/Extension/asm/asm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __ASM_H__
-#define __ASM_H__
-
-#define OP_JMP 0xE9
-#define OP_JMP_SIZE 5
-
-#define OP_NOP 0x90
-#define OP_NOP_SIZE 1
-
-#define OP_PREFIX 0xFF
-#define OP_JMP_SEG 0x25
-
-#define OP_JMP_BYTE 0xEB
-#define OP_JMP_BYTE_SIZE 2
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-void check_thunks(unsigned char *dest, unsigned char *pc);
-
-//if dest is NULL, returns minimum number of bytes needed to be copied
-//if dest is not NULL, it will copy the bytes to dest as well as fix CALLs and JMPs
-//http://www.devmaster.net/forums/showthread.php?t=2311
-int copy_bytes(unsigned char *func, unsigned char* dest, int required_len);
-
-//insert a specific JMP instruction at the given location
-void inject_jmp(void* src, void* dest);
-
-//fill a given block with NOPs
-void fill_nop(void* src, unsigned int len);
-
-//evaluate a JMP at the target
-void* eval_jump(void* src);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //__ASM_H__
diff --git a/Extension/gsnatives.cpp b/Extension/gsnatives.cpp
index 9c0db4cc..1b00c988 100644
--- a/Extension/gsnatives.cpp
+++ b/Extension/gsnatives.cpp
@@ -199,7 +199,7 @@ static cell_t sm_ForceHeartbeat(IPluginContext *pContext, const cell_t *params)
return 0;
}
- pServer->ForceHeartbeat();
+ //pServer->ForceHeartbeat();
return 1;
}
diff --git a/Extension/swgsdetours.cpp b/Extension/swgsdetours.cpp
index 1bad31cd..0e73f95a 100644
--- a/Extension/swgsdetours.cpp
+++ b/Extension/swgsdetours.cpp
@@ -17,6 +17,8 @@
*/
#include "swgsdetours.h"
+#include "CDetour/detours.h"
+#define DETOUR_CREATE_STATIC_FIXED(name, address) CDetourManager::CreateDetour(GET_STATIC_CALLBACK(name), GET_STATIC_TRAMPOLINE(name), address);
DETOUR_DECL_STATIC0(SteamAPIShutdown, void)
{
diff --git a/Extension/swgsdetours.h b/Extension/swgsdetours.h
index 48aebb02..e758fe7c 100644
--- a/Extension/swgsdetours.h
+++ b/Extension/swgsdetours.h
@@ -19,7 +19,8 @@
#pragma once
#include "smsdk_ext.h"
#include "steam_gameserver.h"
-#include "CDetour/detours.h"
+
+class CDetour;
class SteamWorksGSDetours
{
diff --git a/Extension/swhttp.h b/Extension/swhttp.h
index e9e64ea0..82a79ea1 100644
--- a/Extension/swhttp.h
+++ b/Extension/swhttp.h
@@ -26,7 +26,7 @@ class SteamWorksHTTP :
{
public:
SteamWorksHTTP();
- ~SteamWorksHTTP();
+ virtual ~SteamWorksHTTP();
public:
void OnHandleDestroy(HandleType_t type, void *object);
@@ -40,4 +40,4 @@ class SteamWorksHTTP :
};
#include "swhttprequest.h"
-#include "extension.h"
\ No newline at end of file
+#include "extension.h"
diff --git a/Extension/swhttprequest.h b/Extension/swhttprequest.h
index 78d14e29..2981c206 100644
--- a/Extension/swhttprequest.h
+++ b/Extension/swhttprequest.h
@@ -54,4 +54,4 @@ class SteamWorksHTTPNatives
~SteamWorksHTTPNatives();
};
-#include "extension.h"
\ No newline at end of file
+#include "extension.h"
diff --git a/build/build b/build/build
new file mode 100755
index 00000000..cd034230
--- /dev/null
+++ b/build/build
@@ -0,0 +1,11 @@
+#!/bin/bash
+
+ln -s ../sdk/hl2sdk-manifests ../
+
+python3 ../configure.py -s tf2 \
+ --hl2sdk-root `realpath ../../sdk` \
+ --mms-path ../../sdk/mmsource \
+ --sm-path ../../sdk/sourcemod \
+ --steamworks-path ../../sdk/steamworks \
+ --targets x86,x86_64
+ambuild
diff --git a/build/clean b/build/clean
new file mode 100755
index 00000000..e2fe98a7
--- /dev/null
+++ b/build/clean
@@ -0,0 +1,4 @@
+#!/bin/bash
+rm -rf package .ambuild2 Extension Package
+cd ..
+rm -rf hl2sdk-manifests exception
From bcb600462fdf7f74f2eeadcf3de91d1f4d17768e Mon Sep 17 00:00:00 2001
From: bottiger1 <55270538+bottiger1@users.noreply.github.com>
Date: Tue, 7 May 2024 14:31:17 -0700
Subject: [PATCH 2/3] fix build file
---
build/build | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/build/build b/build/build
index cd034230..f229b1aa 100755
--- a/build/build
+++ b/build/build
@@ -2,10 +2,10 @@
ln -s ../sdk/hl2sdk-manifests ../
-python3 ../configure.py -s tf2 \
+python3 ../configure.py -s sdk2013 \
--hl2sdk-root `realpath ../../sdk` \
--mms-path ../../sdk/mmsource \
--sm-path ../../sdk/sourcemod \
--steamworks-path ../../sdk/steamworks \
- --targets x86,x86_64
+ --target x86_64
ambuild
From 8428a712d010432b81bcea21251339018ada1d3d Mon Sep 17 00:00:00 2001
From: bottiger1 <55270538+bottiger1@users.noreply.github.com>
Date: Mon, 27 May 2024 22:51:37 -0700
Subject: [PATCH 3/3] switch to safetyhook. fix automatic detection of
libsteam_api
---
AMBuildScript | 4 +++-
Extension/AMBuilder | 11 +++--------
Extension/swgameserver.cpp | 34 ++++++++++++++++++++++++++++++++--
build/build | 1 +
4 files changed, 39 insertions(+), 11 deletions(-)
diff --git a/AMBuildScript b/AMBuildScript
index 160976e9..66717910 100644
--- a/AMBuildScript
+++ b/AMBuildScript
@@ -157,7 +157,7 @@ class SteamWorksConfig(object):
'-fPIC',
]
cxx.cxxflags += [
- '-std=c++17',
+ '-std=c++20',
]
have_gcc = cxx.vendor == 'gcc'
@@ -271,6 +271,8 @@ class SteamWorksConfig(object):
compiler.includes += [
os.path.join(context.currentSourcePath),
os.path.join(context.currentSourcePath, 'sdk'),
+ os.path.join(context.currentSourcePath, 'CDetour'),
+
os.path.join(self.sm_root, 'public'),
os.path.join(self.sm_root, 'public', 'extensions'),
os.path.join(self.sm_root, 'sourcepawn', 'include'),
diff --git a/Extension/AMBuilder b/Extension/AMBuilder
index 71aa9b96..a16f21a8 100644
--- a/Extension/AMBuilder
+++ b/Extension/AMBuilder
@@ -17,14 +17,9 @@ project.sources += [
'swgchooks.cpp',
'sdk/smsdk_ext.cpp',
- os.path.join(SteamWorks.sm_root, 'public', 'CDetour', 'detours.cpp'),
- os.path.join(SteamWorks.sm_root, 'public', 'asm', 'asm.c'),
- os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'decode.c'),
- os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'itab.c'),
- os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'syn-att.c'),
- os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'syn-intel.c'),
- os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'syn.c'),
- os.path.join(SteamWorks.sm_root, 'public', 'libudis86', 'udis86.c'),
+ 'CDetour/Zydis.c',
+ 'CDetour/safetyhook.cpp',
+ 'CDetour/detours.cpp',
]
for sdk_name in SteamWorks.sdks:
diff --git a/Extension/swgameserver.cpp b/Extension/swgameserver.cpp
index aa66b353..55f7377a 100644
--- a/Extension/swgameserver.cpp
+++ b/Extension/swgameserver.cpp
@@ -17,6 +17,8 @@
*/
#include "swgameserver.h"
+#include
+#include
static void GetGameSpecificConfigInterface(const char *pName, const char *&pVersion)
{
@@ -62,7 +64,9 @@ void SteamWorksGameServer::Reset(void)
ISteamClient *SteamWorksGameServer::GetSteamClient(void)
{
if (g_pSteamClientGameServer != NULL)
+ {
return g_pSteamClientGameServer;
+ }
/*
The following is assumed from an unreleased version of the SteamWorks SDK, first seen (and reversed) in CS:GO.
@@ -105,10 +109,14 @@ ISteamClient *SteamWorksGameServer::GetSteamClient(void)
}
if (pGSInternalCreateAddress != NULL)
+ {
this->m_pClient = static_cast((*pGSInternalCreateAddress)(STEAMCLIENT_INTERFACE_VERSION));
+ }
if (this->m_pClient == NULL && pInternalCreateAddress != NULL)
+ {
this->m_pClient = static_cast((*pInternalCreateAddress)(STEAMCLIENT_INTERFACE_VERSION));
+ }
}
return this->m_pClient;
@@ -123,7 +131,7 @@ ISteamGameServer *SteamWorksGameServer::GetGameServer(void)
GetUserAndPipe(hSteamUser, hSteamPipe);
const char *pVersion = STEAMGAMESERVER_INTERFACE_VERSION;
- GetGameSpecificConfigInterface("SteamGameServerInterfaceVersion", pVersion);
+ //GetGameSpecificConfigInterface("SteamGameServerInterfaceVersion", pVersion);
this->m_pGameServer = this->GetSteamClient()->GetISteamGameServer(hSteamUser, hSteamPipe, pVersion);
}
@@ -230,14 +238,36 @@ void SteamWorksGameServer::GetUserAndPipe(HSteamUser &hSteamUser, HSteamPipe &hS
hSteamPipe = SteamGameServer_GetHSteamPipe();
}
+std::string get_loaded_library_path(const std::string& libname) {
+ struct search_data_t {
+ const std::string& name;
+ std::string path;
+ } search_data { libname, "" };
+
+ auto callback = [](struct dl_phdr_info *info, size_t size, void *data) -> int {
+ search_data_t *search_data = static_cast(data);
+ if (strstr(info->dlpi_name, search_data->name.c_str())) {
+ search_data->path = info->dlpi_name;
+ return 1; // Stop iteration
+ }
+ return 0; // Continue iteration
+ };
+
+ dl_iterate_phdr(callback, &search_data);
+
+ return search_data.path;
+}
+
const char *SteamWorksGameServer::GetLibraryPath(void)
{
static const char *pLibSteamPath = NULL;
+ static std::string libSteamPath;
if (pLibSteamPath == NULL)
{
#if defined POSIX
- pLibSteamPath = "./bin/libsteam_api.so";
+ libSteamPath = get_loaded_library_path("libsteam_api.so");
+ pLibSteamPath = libSteamPath.c_str();
#elif defined WIN32_LEAN_AND_MEAN
pLibSteamPath = "./bin/steam_api.dll"; /* Naming from SteamTools. */
#endif
diff --git a/build/build b/build/build
index f229b1aa..d011c995 100755
--- a/build/build
+++ b/build/build
@@ -1,6 +1,7 @@
#!/bin/bash
ln -s ../sdk/hl2sdk-manifests ../
+ln -s ../../sdk/CDetour ../Extension
python3 ../configure.py -s sdk2013 \
--hl2sdk-root `realpath ../../sdk` \