diff --git a/AMBuildScript b/AMBuildScript
index 2e5a74b..74f49b6 100644
--- a/AMBuildScript
+++ b/AMBuildScript
@@ -16,9 +16,9 @@ class MMS:
 		self.sdkInfo['ep2v'] =  {'sdk': 'HL2SDKOBVALVE',   'ext': '2.ep2v',  'def': '4',
 		                         'name': 'ORANGEBOXVALVE', 'platform': ['windows', 'linux', 'darwin']}
 		self.sdkInfo['l4d'] =   {'sdk': 'HL2SDKL4D',       'ext': '2.l4d',   'def': '5',
-		                         'name': 'LEFT4DEAD',      'platform': ['windows', 'linux']}
+		                         'name': 'LEFT4DEAD',      'platform': ['windows', 'linux', 'darwin']}
 		self.sdkInfo['l4d2'] =  {'sdk': 'HL2SDKL4D2',      'ext': '2.l4d2',  'def': '6',
-		                         'name': 'LEFT4DEAD2',     'platform': ['windows', 'linux']}
+		                         'name': 'LEFT4DEAD2',     'platform': ['windows', 'linux', 'darwin']}
 		self.sdkInfo['darkm'] = {'sdk': 'HL2SDK-DARKM',    'ext': '2.darkm', 'def': '2',
 		                         'name': 'DARKMESSIAH',    'platform': ['windows']}
 		self.sdkInfo['swarm'] = {'sdk': 'HL2SDK-SWARM',    'ext': '2.swarm', 'def': '7',
@@ -33,10 +33,10 @@ class MMS:
 			if AMBuild.target['platform'] != 'darwin':
 				envvars['HL2SDK'] = 'hl2sdk'
 				envvars['HL2SDKOB'] = 'hl2sdk-ob'
-				envvars['HL2SDKL4D'] = 'hl2sdk-l4d'
-				envvars['HL2SDKL4D2'] = 'hl2sdk-l4d2'
 
 			envvars['HL2SDKOBVALVE'] = 'hl2sdk-ob-valve'
+			envvars['HL2SDKL4D'] = 'hl2sdk-l4d'
+			envvars['HL2SDKL4D2'] = 'hl2sdk-l4d2'
 
 			#Dark Messiah is Windows-only
 			if AMBuild.target['platform'] == 'windows':
@@ -83,6 +83,7 @@ class MMS:
 				self.compiler.AddToListVar('CFLAGS', '-mfpmath=sse')
 				self.compiler.AddToListVar('CFLAGS', '-msse')
 				self.compiler.AddToListVar('CFLAGS', '-m32')
+				self.compiler.AddToListVar('POSTLINKFLAGS', '-m32')
 				self.compiler.AddToListVar('CFLAGS', '-static-libgcc')
 				self.compiler.AddToListVar('CXXFLAGS', '-fno-exceptions')
 				self.compiler.AddToListVar('CXXFLAGS', '-fno-rtti')
@@ -218,7 +219,7 @@ class MMS:
 			else:
 				staticLibs = os.path.join(sdkPath, 'lib', 'linux')
 			workFolder = os.path.join(AMBuild.outputFolder, job.workFolder)
-			if sdk == 'ep2v' or sdk == 'l4d2':
+			if sdk in ['ep2v', 'l4d', 'l4d2']:
 				for i in ['tier1_i486.a', 'libvstdlib.so', 'libtier0.so']:
 					link = os.path.join(workFolder, i)
 					target = os.path.join(staticLibs, i)
@@ -300,7 +301,7 @@ class MMS:
 		if not noLink:
 			if AMBuild.target['platform'] == 'linux':
 				compiler['POSTLINKFLAGS'][0:0] = ['-lm']
-				if sdk == 'ep2v' or sdk == 'l4d2':
+				if sdk in ['ep2v', 'l4d', 'l4d2']:
 					compiler['POSTLINKFLAGS'][0:0] = ['libtier0.so']
 					compiler['POSTLINKFLAGS'][0:0] = ['libvstdlib.so']
 				else:
diff --git a/core/AMBuilder b/core/AMBuilder
index 471cecc..be83383 100644
--- a/core/AMBuilder
+++ b/core/AMBuilder
@@ -23,6 +23,10 @@ for i in MMS.sdkInfo:
 		'provider/provider_ep2.cpp',
 		'sourcehook/sourcehook.cpp',
 		'sourcehook/sourcehook_hookmangen.cpp',
+		'sourcehook/sourcehook_impl_chookidman.cpp',
+		'sourcehook/sourcehook_impl_chookmaninfo.cpp',
+		'sourcehook/sourcehook_impl_cproto.cpp',
+		'sourcehook/sourcehook_impl_cvfnptr.cpp',
 		'gamedll_bridge.cpp',
 		'vsp_bridge.cpp'
 		]
diff --git a/core/sourcehook/generate/sh_memfuncinfo.h b/core/sourcehook/generate/sh_memfuncinfo.h
index 8614d93..13c40a6 100644
--- a/core/sourcehook/generate/sh_memfuncinfo.h
+++ b/core/sourcehook/generate/sh_memfuncinfo.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/generate/sh_memfuncinfo.hxx b/core/sourcehook/generate/sh_memfuncinfo.hxx
index 19e6e1e..086a25d 100644
--- a/core/sourcehook/generate/sh_memfuncinfo.hxx
+++ b/core/sourcehook/generate/sh_memfuncinfo.hxx
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/generate/shworker.exe b/core/sourcehook/generate/shworker.exe
index a251da1..4362910 100644
Binary files a/core/sourcehook/generate/shworker.exe and b/core/sourcehook/generate/shworker.exe differ
diff --git a/core/sourcehook/generate/shworker/msvc9/shworker.sln b/core/sourcehook/generate/shworker/msvc9/shworker.sln
new file mode 100644
index 0000000..87f5ddc
--- /dev/null
+++ b/core/sourcehook/generate/shworker/msvc9/shworker.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shworker", "shworker.vcproj", "{7CD76E64-A9DF-47DB-8A68-36297C67E557}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Debug|Win32.Build.0 = Debug|Win32
+		{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Release|Win32.ActiveCfg = Release|Win32
+		{7CD76E64-A9DF-47DB-8A68-36297C67E557}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/core/sourcehook/generate/shworker/msvc9/shworker.vcproj b/core/sourcehook/generate/shworker/msvc9/shworker.vcproj
new file mode 100644
index 0000000..b174ea4
--- /dev/null
+++ b/core/sourcehook/generate/shworker/msvc9/shworker.vcproj
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9,00"
+	Name="shworker"
+	ProjectGUID="{7CD76E64-A9DF-47DB-8A68-36297C67E557}"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;stricmp=_stricmp"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/shworker.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/shworker.pdb"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="2"
+				InlineFunctionExpansion="1"
+				OmitFramePointers="true"
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE;stricmp=_stricmp"
+				StringPooling="true"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+				DisableSpecificWarnings="4996"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/shworker.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+			>
+			<File
+				RelativePath="..\fd_hopter.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\shworker.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc"
+			>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/core/sourcehook/generate/shworker/shworker.cpp b/core/sourcehook/generate/shworker/shworker.cpp
index be328ef..5e0047c 100644
--- a/core/sourcehook/generate/shworker/shworker.cpp
+++ b/core/sourcehook/generate/shworker/shworker.cpp
@@ -743,7 +743,7 @@ int main(int argc, const char **argv)
 
 	const char *action = argv[1];
 
-	if (strcasecmp(action, "hopter") == 0)
+	if (stricmp(action, "hopter") == 0)
 	{
 		const char *filenamein = argv[2];
 		const char *filenameout = argv[3];
@@ -751,7 +751,7 @@ int main(int argc, const char **argv)
 
 		return action_hopter(argsnum, filenamein, filenameout); 
 	}
-	else if (strcasecmp(action, "iter") == 0)
+	else if (stricmp(action, "iter") == 0)
 	{
 		const char *filenamein = argv[2];
 		const char *filenameout = argv[3];
diff --git a/core/sourcehook/generate/sourcehook.h b/core/sourcehook/generate/sourcehook.h
index 275cdf4..ba28315 100644
--- a/core/sourcehook/generate/sourcehook.h
+++ b/core/sourcehook/generate/sourcehook.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -307,6 +307,20 @@ namespace SourceHook
 		};
 	};
 
+	template <class T> struct ReferenceUtil
+	{
+		typedef T plain_type;
+		typedef T* pointer_type;
+		typedef T& reference_type;
+	};
+
+	template <class T> struct ReferenceUtil<T&>
+	{
+		typedef T plain_type;
+		typedef T* pointer_type;
+		typedef T& reference_type;
+	};
+
 	struct IHookContext
 	{
 		virtual ISHDelegate *GetNext() = 0;
@@ -480,7 +494,7 @@ namespace SourceHook
 		*	@return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
 		*		when the hook func is being called as part of a recall
 		*/
-		virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry,
+		virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr,
 			META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
 			const void *origRetPtr, void *overrideRetPtr) = 0;
 
@@ -579,10 +593,14 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 
 // only call these from the hook handlers directly!
 
+#define MAKE_NOREF_VALUE(rettype) \
+	*reinterpret_cast< ::SourceHook::ReferenceUtil<rettype>::pointer_type >(0)
+
 // If a hook on a function which returns a reference does not want to specify a return value,
 // it can use this macro.
 //   ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!!
-#define RETURN_META_NOREF(result, rettype)	do { SET_META_RESULT(result); return reinterpret_cast<rettype>(*SH_GLOB_SHPTR); } while(0)
+#define RETURN_META_NOREF(result, rettype) \
+	RETURN_META_VALUE(result, MAKE_NOREF_VALUE(rettype))
 
 // Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
 // Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
@@ -1163,7 +1181,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN0(hookname, rettype) \
@@ -1196,7 +1214,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN0_vafmt(hookname, rettype) \
@@ -1368,7 +1386,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN1(hookname, rettype, param1) \
@@ -1401,7 +1419,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN1_vafmt(hookname, rettype, param1) \
@@ -1573,7 +1591,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN2(hookname, rettype, param1, param2) \
@@ -1606,7 +1624,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN2_vafmt(hookname, rettype, param1, param2) \
@@ -1778,7 +1796,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN3(hookname, rettype, param1, param2, param3) \
@@ -1811,7 +1829,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN3_vafmt(hookname, rettype, param1, param2, param3) \
@@ -1983,7 +2001,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN4(hookname, rettype, param1, param2, param3, param4) \
@@ -2016,7 +2034,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN4_vafmt(hookname, rettype, param1, param2, param3, param4) \
@@ -2188,7 +2206,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN5(hookname, rettype, param1, param2, param3, param4, param5) \
@@ -2221,7 +2239,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN5_vafmt(hookname, rettype, param1, param2, param3, param4, param5) \
@@ -2393,7 +2411,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN6(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@@ -2426,7 +2444,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN6_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@@ -2598,7 +2616,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN7(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@@ -2631,7 +2649,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN7_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@@ -2803,7 +2821,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN8(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@@ -2836,7 +2854,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN8_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@@ -3008,7 +3026,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN9(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@@ -3041,7 +3059,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN9_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@@ -3213,7 +3231,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN10(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@@ -3246,7 +3264,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN10_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@@ -3418,7 +3436,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN11(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@@ -3451,7 +3469,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN11_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@@ -3623,7 +3641,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN12(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@@ -3656,7 +3674,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN12_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@@ -3828,7 +3846,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN13(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@@ -3861,7 +3879,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN13_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@@ -4033,7 +4051,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN14(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@@ -4066,7 +4084,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN14_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@@ -4238,7 +4256,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN15(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@@ -4271,7 +4289,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN15_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@@ -4443,7 +4461,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN16(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@@ -4476,7 +4494,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN16_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@@ -6737,12 +6755,6 @@ SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Para
 
 namespace SourceHook
 {
-	template <class RetType>
-	void SetOverrideResult(ISourceHook *shptr, const RetType res)
-	{
-		*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
-	}
-
 	// SetOverrideResult used to be implemented like this:
 	//  SetOverrideResult(shptr, memfuncptr, return);
 	//  normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference
@@ -6767,6 +6779,14 @@ namespace SourceHook
 		}
 	};
 
+	// For manual hooks:
+	// The rettype is passed in manually
+	template <class RetType>
+	OverrideFunctor<RetType> SetOverrideResult()
+	{
+		return OverrideFunctor<RetType>();
+	}
+
 	template <class Iface, class RetType>
 	OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)())
 	{
diff --git a/core/sourcehook/generate/sourcehook.hxx b/core/sourcehook/generate/sourcehook.hxx
index 60bf039..921942c 100755
--- a/core/sourcehook/generate/sourcehook.hxx
+++ b/core/sourcehook/generate/sourcehook.hxx
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -307,6 +307,20 @@ namespace SourceHook
 		};
 	};
 
+	template <class T> struct ReferenceUtil
+	{
+		typedef T plain_type;
+		typedef T* pointer_type;
+		typedef T& reference_type;
+	};
+
+	template <class T> struct ReferenceUtil<T&>
+	{
+		typedef T plain_type;
+		typedef T* pointer_type;
+		typedef T& reference_type;
+	};
+
 	struct IHookContext
 	{
 		virtual ISHDelegate *GetNext() = 0;
@@ -480,7 +494,7 @@ namespace SourceHook
 		*	@return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
 		*		when the hook func is being called as part of a recall
 		*/
-		virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry,
+		virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr,
 			META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
 			const void *origRetPtr, void *overrideRetPtr) = 0;
 
@@ -579,10 +593,14 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 
 // only call these from the hook handlers directly!
 
+#define MAKE_NOREF_VALUE(rettype) \
+	*reinterpret_cast< ::SourceHook::ReferenceUtil<rettype>::pointer_type >(0)
+
 // If a hook on a function which returns a reference does not want to specify a return value,
 // it can use this macro.
 //   ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!!
-#define RETURN_META_NOREF(result, rettype)	do { SET_META_RESULT(result); return reinterpret_cast<rettype>(*SH_GLOB_SHPTR); } while(0)
+#define RETURN_META_NOREF(result, rettype) \
+	RETURN_META_VALUE(result, MAKE_NOREF_VALUE(rettype))
 
 // Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
 // Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
@@ -1163,7 +1181,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN$1(hookname, rettype@[$2,1,$1:, param$2@]) \
@@ -1196,7 +1214,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN$1_vafmt(hookname, rettype@[$2,1,$1:, param$2@]) \
@@ -1415,12 +1433,6 @@ SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(@[$2,1,$1|, :Param$2@]@[$1!=0:, @]..
 
 namespace SourceHook
 {
-	template <class RetType>
-	void SetOverrideResult(ISourceHook *shptr, const RetType res)
-	{
-		*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
-	}
-
 	// SetOverrideResult used to be implemented like this:
 	//  SetOverrideResult(shptr, memfuncptr, return);
 	//  normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference
@@ -1444,6 +1456,14 @@ namespace SourceHook
 			*reinterpret_cast<typename ReferenceCarrier<T&>::type *>(shptr->GetOverrideRetPtr()) = res;
 		}
 	};
+
+	// For manual hooks:
+	// The rettype is passed in manually
+	template <class RetType>
+	OverrideFunctor<RetType> SetOverrideResult()
+	{
+		return OverrideFunctor<RetType>();
+	}
 @[$1,0,$a:
 	template <class Iface, class RetType@[$2,1,$1:, class Param$2@]>
 	OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)(@[$2,1,$1|, :Param$2@]))
diff --git a/core/sourcehook/sh_list.h b/core/sourcehook/sh_list.h
index 1e56b9d..21d57c0 100644
--- a/core/sourcehook/sh_list.h
+++ b/core/sourcehook/sh_list.h
@@ -1,5 +1,5 @@
 /* ======== SourceMM ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sh_memfuncinfo.h b/core/sourcehook/sh_memfuncinfo.h
index 8614d93..13c40a6 100644
--- a/core/sourcehook/sh_memfuncinfo.h
+++ b/core/sourcehook/sh_memfuncinfo.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sh_memory.h b/core/sourcehook/sh_memory.h
index f69d273..f3e03d0 100644
--- a/core/sourcehook/sh_memory.h
+++ b/core/sourcehook/sh_memory.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sh_pagealloc.h b/core/sourcehook/sh_pagealloc.h
index 15400fc..0becac7 100644
--- a/core/sourcehook/sh_pagealloc.h
+++ b/core/sourcehook/sh_pagealloc.h
@@ -1,6 +1,9 @@
 #ifndef __SH_PAGEALLOC_H__
 #define __SH_PAGEALLOC_H__
 
+#include "sh_list.h"
+#include "sh_memory.h"
+
 # if SH_XP == SH_XP_WINAPI
 #		include <windows.h>
 # elif SH_XP == SH_XP_POSIX
@@ -53,6 +56,7 @@ namespace SourceHook
 			bool isolated;					// may contain only one AU
 			size_t minAlignment;
 			AUList allocUnits;
+			bool isRE;						// true: RE, otherwise: RW
 
 			void CheckGap(size_t gap_begin, size_t gap_end, size_t reqsize,
 				size_t &smallestgap_pos, size_t &smallestgap_size, size_t &outAlignBytes)
@@ -122,9 +126,11 @@ namespace SourceHook
 					void *alignedAUBegin = reinterpret_cast<void*>(
 						AUBegin + ((minAlignment - AUBegin % minAlignment) % minAlignment)
 						);
-					
+
 					if (addr == alignedAUBegin)
 					{
+						DebugCleanMemory(reinterpret_cast<unsigned char*>(startPtr) + iter->begin_offset,
+							iter->size);
 						allocUnits.erase(iter);
 						return true;
 					}
@@ -133,6 +139,26 @@ namespace SourceHook
 				return false;
 			}
 
+			void DebugCleanMemory(unsigned char* start, size_t size)
+			{
+				bool wasRE = isRE;
+				if (isRE)
+				{
+					SetRW();
+				}
+
+				unsigned char* end = start + size;
+				for (unsigned char* p = start; p != end; ++p)
+				{
+					*p = 0xCC;
+				}
+
+				if (wasRE)
+				{
+					SetRE();
+				}
+			}
+
 			bool Contains(void *addr)
 			{
 				return addr >= startPtr && addr < reinterpret_cast<void*>(reinterpret_cast<char*>(startPtr) + size);
@@ -146,6 +172,18 @@ namespace SourceHook
 				VirtualFree(startPtr, 0, MEM_RELEASE);
 #endif
 			}
+
+			void SetRE()
+			{
+				SetMemAccess(startPtr, size, SH_MEM_READ | SH_MEM_EXEC);
+				isRE = true;
+			}
+
+			void SetRW()
+			{
+				SetMemAccess(startPtr, size, SH_MEM_READ | SH_MEM_WRITE);
+				isRE = false;
+			}
 		};
 
 		typedef List<AllocatedRegion> ARList;
@@ -178,6 +216,7 @@ namespace SourceHook
 
 			if (newRegion.startPtr)
 			{
+				newRegion.SetRW();
 				m_Regions.push_back(newRegion);
 				return true;
 			}
@@ -210,7 +249,7 @@ namespace SourceHook
 		}
 
 	public:
-		CPageAlloc(size_t minAlignment = 1 /* power of 2 */ ) : m_MinAlignment(minAlignment)
+		CPageAlloc(size_t minAlignment = 4 /* power of 2 */ ) : m_MinAlignment(minAlignment)
 		{
 #if SH_XP == SH_XP_POSIX
 			m_PageSize = sysconf(_SC_PAGESIZE);
@@ -262,7 +301,7 @@ namespace SourceHook
 			{
 				if (iter->Contains(ptr))
 				{
-					SetMemAccess(iter->startPtr, iter->size, SH_MEM_READ | SH_MEM_EXEC);
+					iter->SetRE();
 					break;
 				}
 			}
@@ -274,7 +313,7 @@ namespace SourceHook
 			{
 				if (iter->Contains(ptr))
 				{
-					SetMemAccess(iter->startPtr, iter->size, SH_MEM_READ | SH_MEM_WRITE);
+					iter->SetRW();
 					break;
 				}
 			}
diff --git a/core/sourcehook/sh_stack.h b/core/sourcehook/sh_stack.h
index e6269e6..5322db2 100644
--- a/core/sourcehook/sh_stack.h
+++ b/core/sourcehook/sh_stack.h
@@ -1,5 +1,5 @@
 /* ======== SourceMM ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sh_string.h b/core/sourcehook/sh_string.h
index 79f96b8..6d6a8a5 100755
--- a/core/sourcehook/sh_string.h
+++ b/core/sourcehook/sh_string.h
@@ -1,5 +1,5 @@
 /* ======== SourceMM ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sh_tinyhash.h b/core/sourcehook/sh_tinyhash.h
index 67f3adf..60b919c 100644
--- a/core/sourcehook/sh_tinyhash.h
+++ b/core/sourcehook/sh_tinyhash.h
@@ -1,5 +1,5 @@
 /* ======== SourceMM ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook.cpp b/core/sourcehook/sourcehook.cpp
index 8bb9035..58f8086 100644
--- a/core/sourcehook/sourcehook.cpp
+++ b/core/sourcehook/sourcehook.cpp
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -41,373 +41,33 @@ namespace SourceHook
 
 	namespace Impl
 	{
-		//////////////////////////////////////////////////////////////////////////
-		// CProto
-		//////////////////////////////////////////////////////////////////////////
-		void CProto::Fill(const ProtoInfo *pProto)
-		{
-			if (pProto == NULL)
-				m_Version = -1;
-
-			m_ParamsPassInfo.clear();
-
-			if (pProto->paramsPassInfo[0].size == 0)
-			{
-				// Version 1
-				m_Version = 0;
-				m_Convention = pProto->convention;
-				m_NumOfParams = pProto->numOfParams;
-
-				m_RetPassInfo.size = pProto->retPassInfo.size;
-				m_RetPassInfo.type = pProto->retPassInfo.type;
-				m_RetPassInfo.flags = GetRealFlags(pProto->retPassInfo);
-
-				m_RetPassInfo.pNormalCtor = NULL;
-				m_RetPassInfo.pCopyCtor = NULL;
-				m_RetPassInfo.pDtor = NULL;
-				m_RetPassInfo.pAssignOperator = NULL;
-
-				
-				m_ParamsPassInfo.resize(pProto->numOfParams);
-
-				for (int i = 1; i <= pProto->numOfParams; ++i)
-				{
-					m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
-					m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
-					m_ParamsPassInfo[i-1].flags = GetRealFlags(pProto->paramsPassInfo[i]);
-
-					m_ParamsPassInfo[i-1].pNormalCtor = NULL;
-					m_ParamsPassInfo[i-1].pCopyCtor = NULL;
-					m_ParamsPassInfo[i-1].pDtor = NULL;
-					m_ParamsPassInfo[i-1].pAssignOperator = NULL;
-				}
-			}
-			else if (pProto->paramsPassInfo[0].size == 1)
-			{
-				// Version 2
-				m_Version = 1;
-				m_Convention = pProto->convention;
-				m_NumOfParams = pProto->numOfParams;
-
-				m_RetPassInfo.size = pProto->retPassInfo.size;
-				m_RetPassInfo.type = pProto->retPassInfo.type;
-				m_RetPassInfo.flags = pProto->retPassInfo.flags;
-
-				m_RetPassInfo.pNormalCtor = pProto->retPassInfo2.pNormalCtor;
-				m_RetPassInfo.pCopyCtor = pProto->retPassInfo2.pCopyCtor;
-				m_RetPassInfo.pDtor = pProto->retPassInfo2.pDtor;
-				m_RetPassInfo.pAssignOperator = pProto->retPassInfo2.pAssignOperator;
-
-				m_ParamsPassInfo.resize(pProto->numOfParams);
-
-				for (int i = 1; i <= pProto->numOfParams; ++i)
-				{
-					m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
-					m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
-					m_ParamsPassInfo[i-1].flags = pProto->paramsPassInfo[i].flags;
-
-					m_ParamsPassInfo[i-1].pNormalCtor = pProto->paramsPassInfo2[i].pNormalCtor;
-					m_ParamsPassInfo[i-1].pCopyCtor = pProto->paramsPassInfo2[i].pCopyCtor;
-					m_ParamsPassInfo[i-1].pDtor = pProto->paramsPassInfo2[i].pDtor;
-					m_ParamsPassInfo[i-1].pAssignOperator = pProto->paramsPassInfo2[i].pAssignOperator;
-				}
-			}
-			else
-			{
-				// Unknown
-				m_Version = -1;
-			}
-		}
-
-		// Basic compat test
-		// Other than this, we assume that the plugins know what they're doing
-		bool CProto::operator == (const CProto &other) const
-		{
-			if (m_Version < 0 || other.GetVersion() < 0)
-				return false;
-
-			if (m_NumOfParams != other.GetNumOfParams())
-				return false;
-
-			if (m_Convention != ProtoInfo::CallConv_Unknown && other.GetConvention() != ProtoInfo::CallConv_Unknown &&
-				m_Convention != other.GetConvention())
-				return false;
-
-			if (GetRealSize(GetRet()) != GetRealSize(other.GetRet()))
-				return false;
-
-			for (int i = 0; i < m_NumOfParams; ++i)
-			{
-				if (GetRealSize(GetParam(i)) != GetRealSize(other.GetParam(i)))
-					return false;
-				if (GetParam(i).type != PassInfo::PassType_Unknown && other.GetParam(i).type != PassInfo::PassType_Unknown)
-				{
-					if (GetParam(i).type != other.GetParam(i).type)
-						return false;
-					if (GetParam(i).flags != other.GetParam(i).flags)
-						return false;
-				}
-			}
-
-			return true;
-		}
-
-		bool CProto::ExactlyEqual(const CProto &other) const
-		{
-			if (m_Version != other.m_Version ||
-				m_NumOfParams != other.m_NumOfParams ||
-				m_Convention != other.m_Convention ||
-				GetRet() != other.GetRet())
-			{
-				return false;
-			}
-
-			for (int i = 0; i < m_NumOfParams; ++i)
-			{
-				if(GetParam(i) != other.GetParam(i))
-					return false;
-			}
-
-			return true;
-		}
-		
-		//////////////////////////////////////////////////////////////////////////
-		// CHookManager
-		//////////////////////////////////////////////////////////////////////////
-		void CHookManager::SetInfo(int hookman_version, int vtbloffs, int vtblidx,
-			ProtoInfo *proto, void *hookfunc_vfnptr)
-		{
-			m_Version = hookman_version;
-			m_VtblOffs = vtbloffs;
-			m_VtblIdx = vtblidx;
-			m_Proto = proto;
-			m_HookfuncVfnptr = hookfunc_vfnptr;
-		}
-
 		//////////////////////////////////////////////////////////////////////////
 		// CVfnPtrList
 		//////////////////////////////////////////////////////////////////////////
 
-		CVfnPtr &CVfnPtrList::GetVfnPtr(void *vfnptr)
+		CVfnPtr *CVfnPtrList::GetVfnPtr(void *vfnptr)
 		{
 			iterator iter = find(vfnptr);
 			if (iter == end())
 			{
+				// No vfnptr info object found
+				// --> create a new one
 				CVfnPtr newVfnPtr(vfnptr);
-				push_back(newVfnPtr);
-
-				return back();
-			}
-			else
-			{
-				return *iter;
-			}
-		}
-		//////////////////////////////////////////////////////////////////////////
-		// CVfnPtr
-		//////////////////////////////////////////////////////////////////////////
-		
-		void CVfnPtr::AddHookMan(CHookManager *pHookMan)
-		{
-			List<CHookManager*>::iterator iter;
-
-			// Don't accept invalid hook managers
-			if (!*pHookMan)
-				return;
-
-			// Check whether this hook manager already exists; if yes, ignore.
-			iter = m_HookMans.find(pHookMan);
-			if (iter != m_HookMans.end())
-				return;
-
-			// It doesn't -> add it. Add it to the end of its version group.
-			for (iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
-			{
-				if ((*iter)->GetVersion() < pHookMan->GetVersion())
-					break;
-			}
-
-			bool isBeginning = iter == m_HookMans.begin();
-
-			m_HookMans.insert(iter, pHookMan);
-
-			if (isBeginning)
-			{
-				pHookMan->IncrRef(this);
-				if (m_HookMans.size() > 1)
+				if (newVfnPtr.Init())
 				{
-					// If another hookman was used until now but this one is better
-					// (which it is because it's the first -> it has a higher version)
-					// -> switch!
+					push_back(newVfnPtr);
 
-					List<CHookManager*>::iterator second = m_HookMans.begin();
-					++second;
-
-					(*second)->DecrRef(this);
-				}
-
-				// Make sure that this vfnptr points at it
-				Patch(pHookMan->GetHookFunc());
-			}
-		}
-
-		bool CVfnPtr::HookManRemoved(CHookManager *pHookMan)
-		{
-			// Don't accept invalid hook managers
-			if (!*pHookMan)
-				return true;
-
-			List<CHookManager*>::iterator iter = m_HookMans.find(pHookMan);
-			if (iter == m_HookMans.end())
-				return true;							// Didn't exist here anyway
-
-			if (iter == m_HookMans.begin())
-			{
-				// It is the first one!
-				pHookMan->DecrRef(this);
-				m_HookMans.erase(iter);
-
-				if (m_HookMans.empty())
-					return false;				// No more hookmans -> let SH delete us
-
-				// Activate second -> now first hookman
-				m_HookMans.front()->IncrRef(this);
-				Patch(m_HookMans.front()->GetHookFunc());
-			}
-			else
-			{
-				m_HookMans.erase(iter);
-			}
-			return true;
-		}
-
-		bool CVfnPtr::Patch(void *newValue)
-		{
-			if (!SetMemAccess(m_Ptr, sizeof(void*), SH_MEM_READ | SH_MEM_WRITE))
-			{
-				return false;
-			}
-
-			*reinterpret_cast<void**>(m_Ptr) = newValue;
-
-			return true;
-		}
-
-		CIface &CVfnPtr::GetIface(void *iface)
-		{
-			List<CIface>::iterator iter = m_IfaceList.find(iface);
-			if (iter == m_IfaceList.end())
-			{
-				CIface newIface(iface);
-				if (iface == NULL)
-				{
-					m_IfaceList.push_front(newIface);
-					return m_IfaceList.front();
+					return &(back());
 				}
 				else
 				{
-					m_IfaceList.push_back(newIface);
-					return m_IfaceList.back();
+					// Initialization failed.
+					return NULL;
 				}
 			}
 			else
 			{
-				return *iter;
-			}
-		}
-
-		//////////////////////////////////////////////////////////////////////////
-		// CHookIdManager
-		//////////////////////////////////////////////////////////////////////////
-		CHookIDManager::CHookIDManager()
-		{
-		}
-
-		int CHookIDManager::New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr,
-			void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
-		{
-			Entry tmp(proto, vtbl_offs, vtbl_idx, vfnptr, adjustediface, plug, thisptr_offs, handler, post);
-
-			size_t cursize = m_Entries.size();
-			for (size_t i = 0; i < cursize; ++i)
-			{
-				if (m_Entries[i].isfree)
-				{
-					m_Entries[i] = tmp;
-					return static_cast<int>(i) + 1;
-				}
-			}
-
-			m_Entries.push_back(tmp);
-			return static_cast<int>(m_Entries.size());		// return size() because hookid = id+1 anyway
-		}
-
-		bool CHookIDManager::Remove(int hookid)
-		{
-			int realid = hookid - 1;
-			if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
-				return false;
-
-			m_Entries[realid].isfree = true;
-
-			// :TODO: remove free ids from back sometimes ??
-
-			return true;
-		}
-
-		const CHookIDManager::Entry * CHookIDManager::QueryHook(int hookid)
-		{
-			int realid = hookid - 1;
-			if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
-				return NULL;
-
-			return &m_Entries[realid];
-		}
-
-		void CHookIDManager::FindAllHooks(CVector<int> &output, const CProto &proto, int vtbl_offs,
-			int vtbl_idx, void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
-		{
-			// oh my god, a lot of parameters...
-			size_t cursize = m_Entries.size();
-			for (size_t i = 0; i < cursize; ++i)
-			{
-				if (!m_Entries[i].isfree && m_Entries[i].proto == proto && m_Entries[i].vtbl_offs == vtbl_offs &&
-					m_Entries[i].vtbl_idx == vtbl_idx && m_Entries[i].adjustediface == adjustediface && m_Entries[i].plug == plug &&
-					m_Entries[i].thisptr_offs == thisptr_offs && m_Entries[i].handler->IsEqual(handler) && m_Entries[i].post == post)
-				{
-					output.push_back(static_cast<int>(i) + 1);
-				}
-			}
-		}
-
-		void CHookIDManager::FindAllHooks(CVector<int> &output)
-		{
-			size_t cursize = m_Entries.size();
-			for (size_t i = 0; i < cursize; ++i)
-			{
-				if (!m_Entries[i].isfree)
-					output.push_back(static_cast<int>(i) + 1);
-			}
-		}
-
-		void CHookIDManager::FindAllHooks(CVector<int> &output, Plugin plug)
-		{
-			size_t cursize = m_Entries.size();
-			for (size_t i = 0; i < cursize; ++i)
-			{
-				if (!m_Entries[i].isfree && m_Entries[i].plug == plug)
-					output.push_back(static_cast<int>(i) + 1);
-			}
-		}
-
-
-		void CHookIDManager::RemoveAll(void *vfnptr)
-		{
-			size_t cursize = m_Entries.size();
-			for (size_t i = 0; i < cursize; ++i)
-			{
-				if (!m_Entries[i].isfree && m_Entries[i].vfnptr == vfnptr)
-					m_Entries[i].isfree = true;
+				return &(*iter);
 			}
 		}
 
@@ -480,9 +140,18 @@ namespace SourceHook
 				break;
 			}
 
-			CVfnPtr &vfnPtr = m_VfnPtrs.GetVfnPtr(cur_vfnptr);
-			vfnPtr.AddHookMan(m_HookManList.GetHookMan(hookManager));
-			CIface &ifaceinst = vfnPtr.GetIface(adjustediface);
+			CVfnPtr *vfnPtr = m_VfnPtrs.GetVfnPtr(cur_vfnptr);
+			if (!vfnPtr)
+			{
+				// Could not create the vfnptr info object.
+				// This could be because a thunk generation on GCC
+				// has failed. See sourcehook_impl_cvfnptr.cpp
+				// for details.
+				return false;
+			}
+
+			vfnPtr->AddHookMan(m_HookManList.GetHookMan(hookManager));
+			CIface &ifaceinst = vfnPtr->GetIface(adjustediface);
 
 			// Add the hook
 			CHook hook(plug, thisptr_offs, handler, 
@@ -588,9 +257,7 @@ namespace SourceHook
 						ctx_iter->VfnPtrRemoved(&(*vfnptr_iter));
 					}
 
-					vfnptr_iter->Revert();
-
-					m_VfnPtrs.erase(vfnptr_iter);
+					RevertAndRemoveVfnPtr(vfnptr_iter);
 				}
 			}
 
@@ -598,6 +265,52 @@ namespace SourceHook
 			return true;
 		}
 
+		List<CVfnPtr>::iterator CSourceHookImpl::RevertAndRemoveVfnPtr(List<CVfnPtr>::iterator vfnptr_iter)
+		{
+			ICleanupTask *cleanupTask = vfnptr_iter->GetCleanupTask();
+
+			// Some vfnptrs require cleanup.
+			// Concrete case: on GCC, when the original vtable entry is not even
+			// we generate an even-aligned thunk to call the original function.
+			// If the vfnptr is being removed from a pre hook on the vfnptr
+			// we have to delay the cleanup of this thunk until the hook loop is done
+			// (because the orig function call mechanism is going to use the thunk).
+
+			if (cleanupTask != NULL)
+			{
+				// If this vfnptr is in use in one of the hook loops running at the moment
+				// Schedule it for removal on the DEEPEST hook loop.
+
+				size_t numOfContexts = m_ContextStack.size();
+				// m_ContextStack.at(0) is the deepest hook context
+				// m_ContextStack.at(size-1) = m_ContextStack.front is the uppermost
+
+				bool cleanupImmedieately = true;
+
+				CVfnPtr *vfnPtrObjAddr = &(*vfnptr_iter);
+				for (size_t i = 0; i < numOfContexts; ++i)
+				{
+					CHookContext &context = m_ContextStack.at(i);
+					if (context.pVfnPtr == vfnPtrObjAddr)
+					{
+						// Found a hook context using this vfnptr at the moment.
+						context.m_CleanupTask = cleanupTask;
+						cleanupImmedieately = false;			// Delay the cleanup
+						break;
+					}
+				}
+
+				if (cleanupImmedieately)
+				{
+					cleanupTask->CleanupAndDeleteThis();
+				}
+			}
+
+			// Do the work
+			vfnptr_iter->Revert();
+			return m_VfnPtrs.erase(vfnptr_iter);
+		}
+
 		void CSourceHookImpl::SetRes(META_RES res)
 		{
 			*m_ContextStack.front().pCurRes = res;
@@ -675,10 +388,9 @@ namespace SourceHook
 					// This vfnptr has no more hook managers
 					// and asks to be removed.
 
-					vfnptr_iter->Revert();
-
 					m_HookIDMan.RemoveAll(vfnptr_iter->GetPtr());
-					vfnptr_iter = m_VfnPtrs.erase(vfnptr_iter);
+
+					vfnptr_iter = RevertAndRemoveVfnPtr(vfnptr_iter);
 				}
 				else
 				{
@@ -710,7 +422,12 @@ namespace SourceHook
 		void CSourceHookImpl::ResetIgnoreHooks(void *vfnptr)
 		{
 			if (!m_ContextStack.empty() && m_ContextStack.front().m_State == CHookContext::State_Ignore)
-				m_ContextStack.pop();
+			{
+				// Actually use EndContext
+				// instead of m_ContextStack.pop directly
+				// because it runs the cleanup task if neccesary
+				EndContext(&(m_ContextStack.front()));
+			}
 		}
 
 		void *CSourceHookImpl::GetOrigVfnPtrEntry(void *vfnptr)
@@ -753,7 +470,7 @@ namespace SourceHook
 			curCtx.m_State = CHookContext::State_Dead;
 		}
 
-		IHookContext *CSourceHookImpl::SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry, META_RES *statusPtr,
+		IHookContext *CSourceHookImpl::SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr, META_RES *statusPtr,
 			META_RES *prevResPtr, META_RES *curResPtr, const void *origRetPtr, void *overrideRetPtr)
 		{
 			CHookContext *pCtx = NULL;
@@ -781,7 +498,8 @@ namespace SourceHook
 					}
 					else
 					{
-						*origentry = (*vfnptr_iter)->GetOrigEntry();
+						*origCallAddr = (*vfnptr_iter)->GetOrigCallAddr();
+						oldctx->pVfnPtr = *vfnptr_iter;
 					}
 
 					oldctx->pOrigRet = origRetPtr;
@@ -839,7 +557,7 @@ namespace SourceHook
 			else
 			{
 				pCtx->pVfnPtr = *vfnptr_iter;
-				*origentry = pCtx->pVfnPtr->GetOrigEntry();
+				*origCallAddr = pCtx->pVfnPtr->GetOrigCallAddr();
 				pCtx->pIface = pCtx->pVfnPtr->FindIface(thisptr);
 			}
 
@@ -855,6 +573,9 @@ namespace SourceHook
 
 		void CSourceHookImpl::EndContext(IHookContext *pCtx)
 		{
+			// Do clean up task, if any is associated with this context
+			m_ContextStack.front().DoCleanupTaskAndDeleteIt();
+			// Then remove it
 			m_ContextStack.pop();
 		}
 
@@ -1085,9 +806,22 @@ namespace SourceHook
 		{
 			if (pVfnPtr == vfnptr)
 			{
-				pVfnPtr = NULL;
+				// Don't set pVfnPtr = NULL here!
+				// It may be used still.
+				// RevertAndRemoveVfnPtr uses it to find the hook context
+				// to which to attach the cleanup task of the vfnptr.
+
+				//pVfnPtr = NULL;
 				m_State = State_Dead;
 			}
 		}
+
+		void CHookContext::DoCleanupTaskAndDeleteIt()
+		{
+			if (m_CleanupTask != NULL)
+			{
+				m_CleanupTask->CleanupAndDeleteThis();
+			}
+		}
 	}
 }
diff --git a/core/sourcehook/sourcehook.h b/core/sourcehook/sourcehook.h
index 275cdf4..ba28315 100644
--- a/core/sourcehook/sourcehook.h
+++ b/core/sourcehook/sourcehook.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -307,6 +307,20 @@ namespace SourceHook
 		};
 	};
 
+	template <class T> struct ReferenceUtil
+	{
+		typedef T plain_type;
+		typedef T* pointer_type;
+		typedef T& reference_type;
+	};
+
+	template <class T> struct ReferenceUtil<T&>
+	{
+		typedef T plain_type;
+		typedef T* pointer_type;
+		typedef T& reference_type;
+	};
+
 	struct IHookContext
 	{
 		virtual ISHDelegate *GetNext() = 0;
@@ -480,7 +494,7 @@ namespace SourceHook
 		*	@return Override Return Pointer the hookfunc should use (may differ from overrideRetPtr
 		*		when the hook func is being called as part of a recall
 		*/
-		virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry,
+		virtual IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr,
 			META_RES *statusPtr, META_RES *prevResPtr, META_RES *curResPtr,
 			const void *origRetPtr, void *overrideRetPtr) = 0;
 
@@ -579,10 +593,14 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 
 // only call these from the hook handlers directly!
 
+#define MAKE_NOREF_VALUE(rettype) \
+	*reinterpret_cast< ::SourceHook::ReferenceUtil<rettype>::pointer_type >(0)
+
 // If a hook on a function which returns a reference does not want to specify a return value,
 // it can use this macro.
 //   ONLY USE THIS WITH MRES_IGNORED AND MRES_HANDLED !!!
-#define RETURN_META_NOREF(result, rettype)	do { SET_META_RESULT(result); return reinterpret_cast<rettype>(*SH_GLOB_SHPTR); } while(0)
+#define RETURN_META_NOREF(result, rettype) \
+	RETURN_META_VALUE(result, MAKE_NOREF_VALUE(rettype))
 
 // Why take a memfuncptr instead of iface and func when we have to deduce the iface anyway now?
 // Well, without it, there'd be no way to specify which overloaded version we want in _VALUE
@@ -1163,7 +1181,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN0(hookname, rettype) \
@@ -1196,7 +1214,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN0_vafmt(hookname, rettype) \
@@ -1368,7 +1386,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN1(hookname, rettype, param1) \
@@ -1401,7 +1419,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN1_vafmt(hookname, rettype, param1) \
@@ -1573,7 +1591,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN2(hookname, rettype, param1, param2) \
@@ -1606,7 +1624,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN2_vafmt(hookname, rettype, param1, param2) \
@@ -1778,7 +1796,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN3(hookname, rettype, param1, param2, param3) \
@@ -1811,7 +1829,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN3_vafmt(hookname, rettype, param1, param2, param3) \
@@ -1983,7 +2001,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN4(hookname, rettype, param1, param2, param3, param4) \
@@ -2016,7 +2034,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN4_vafmt(hookname, rettype, param1, param2, param3, param4) \
@@ -2188,7 +2206,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN5(hookname, rettype, param1, param2, param3, param4, param5) \
@@ -2221,7 +2239,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN5_vafmt(hookname, rettype, param1, param2, param3, param4, param5) \
@@ -2393,7 +2411,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN6(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@@ -2426,7 +2444,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN6_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6) \
@@ -2598,7 +2616,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN7(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@@ -2631,7 +2649,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN7_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7) \
@@ -2803,7 +2821,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN8(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@@ -2836,7 +2854,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN8_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8) \
@@ -3008,7 +3026,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN9(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@@ -3041,7 +3059,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN9_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9) \
@@ -3213,7 +3231,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN10(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@@ -3246,7 +3264,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN10_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10) \
@@ -3418,7 +3436,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN11(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@@ -3451,7 +3469,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN11_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11) \
@@ -3623,7 +3641,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN12(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@@ -3656,7 +3674,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN12_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12) \
@@ -3828,7 +3846,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN13(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@@ -3861,7 +3879,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN13_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13) \
@@ -4033,7 +4051,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN14(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@@ -4066,7 +4084,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN14_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14) \
@@ -4238,7 +4256,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN15(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@@ -4271,7 +4289,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN15_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15) \
@@ -4443,7 +4461,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN16(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@@ -4476,7 +4494,7 @@ SourceHook::CallClass<T> *SH_GET_CALLCLASS(T *p)
 		__SourceHook_ParamInfosM_##hookname, 0, __SH_EPI, __SourceHook_ParamInfos2M_##hookname }; \
 	void __SoureceHook_FHM_SetOverrideResult##hookname(::SourceHook::ISourceHook *shptr, rettype value) \
 	{ \
-		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>(shptr, value); \
+		::SourceHook::SetOverrideResult<SH_MFHCls(hookname)::RetType>()(shptr, value); \
 	}
 
 #define SH_DECL_MANUALEXTERN16_vafmt(hookname, rettype, param1, param2, param3, param4, param5, param6, param7, param8, param9, param10, param11, param12, param13, param14, param15, param16) \
@@ -6737,12 +6755,6 @@ SH_CALL2(Y *ptr, MFP mfp, RetType(X::*mfp2)(Param1, Param2, Param3, Param4, Para
 
 namespace SourceHook
 {
-	template <class RetType>
-	void SetOverrideResult(ISourceHook *shptr, const RetType res)
-	{
-		*reinterpret_cast<RetType*>(shptr->GetOverrideRetPtr()) = res;
-	}
-
 	// SetOverrideResult used to be implemented like this:
 	//  SetOverrideResult(shptr, memfuncptr, return);
 	//  normally the compiler can deduce the return type from memfuncptr, but (at least msvc8) failed when it was a reference
@@ -6767,6 +6779,14 @@ namespace SourceHook
 		}
 	};
 
+	// For manual hooks:
+	// The rettype is passed in manually
+	template <class RetType>
+	OverrideFunctor<RetType> SetOverrideResult()
+	{
+		return OverrideFunctor<RetType>();
+	}
+
 	template <class Iface, class RetType>
 	OverrideFunctor<RetType> SetOverrideResult(RetType (Iface::*mfp)())
 	{
diff --git a/core/sourcehook/sourcehook_hookmangen.cpp b/core/sourcehook/sourcehook_hookmangen.cpp
index ecc1765..287a643 100644
--- a/core/sourcehook/sourcehook_hookmangen.cpp
+++ b/core/sourcehook/sourcehook_hookmangen.cpp
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2009 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_hookmangen.h b/core/sourcehook/sourcehook_hookmangen.h
index 6caf2d4..9e565f7 100644
--- a/core/sourcehook/sourcehook_hookmangen.h
+++ b/core/sourcehook/sourcehook_hookmangen.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_hookmangen_x86.h b/core/sourcehook/sourcehook_hookmangen_x86.h
index d9d15d7..e98393b 100644
--- a/core/sourcehook/sourcehook_hookmangen_x86.h
+++ b/core/sourcehook/sourcehook_hookmangen_x86.h
@@ -1,6 +1,6 @@
 /* ======== SourceHook ========
 * vim: set ts=4 :
-* Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
+* Copyright (C) 2004-2010 AlliedModders LLC.  All rights reserved.
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_impl.h b/core/sourcehook/sourcehook_impl.h
index 5d225cc..cf5579e 100644
--- a/core/sourcehook/sourcehook_impl.h
+++ b/core/sourcehook/sourcehook_impl.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -189,6 +189,10 @@ namespace SourceHook
 	{
 		struct CHookContext : IHookContext
 		{
+			CHookContext() : m_CleanupTask(NULL)
+			{
+			}
+
 			enum State
 			{
 				State_Born,
@@ -224,6 +228,8 @@ namespace SourceHook
 
 			bool m_CallOrig;
 
+			ICleanupTask *m_CleanupTask;
+
 			void SkipPaused(List<CHook>::iterator &iter, List<CHook> &list)
 			{
 				while (iter != list.end() && iter->IsPaused())
@@ -238,12 +244,13 @@ namespace SourceHook
 			void *GetOverrideRetPtr();
 			const void *GetOrigRetPtr();
 			bool ShouldCallOrig();
+			void DoCleanupTaskAndDeleteIt();
 		};
 
 		class CVfnPtrList : public List<CVfnPtr>
 		{
 		public:
-			CVfnPtr &GetVfnPtr(void *p);
+			CVfnPtr *GetVfnPtr(void *p);
 		};
 
 		typedef CStack<CHookContext> HookContextStack;
@@ -259,6 +266,7 @@ namespace SourceHook
 
 			bool SetHookPaused(int hookid, bool paused);
 			CHookManList::iterator RemoveHookManager(CHookManList::iterator iter);
+			List<CVfnPtr>::iterator RevertAndRemoveVfnPtr(List<CVfnPtr>::iterator vfnptr_iter);
 		public:
 			CSourceHookImpl();
 			virtual ~CSourceHookImpl();
@@ -308,7 +316,7 @@ namespace SourceHook
 
 			void DoRecall();
 
-			IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origentry, META_RES *statusPtr,
+			IHookContext *SetupHookLoop(IHookManagerInfo *hi, void *vfnptr, void *thisptr, void **origCallAddr, META_RES *statusPtr,
 				META_RES *prevResPtr, META_RES *curResPtr, const void *origRetPtr, void *overrideRetPtr);
 
 			void EndContext(IHookContext *pCtx);
diff --git a/core/sourcehook/sourcehook_impl_chook.h b/core/sourcehook/sourcehook_impl_chook.h
index e1ea76e..2050ed7 100644
--- a/core/sourcehook/sourcehook_impl_chook.h
+++ b/core/sourcehook/sourcehook_impl_chook.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_impl_chookidman.cpp b/core/sourcehook/sourcehook_impl_chookidman.cpp
new file mode 100644
index 0000000..29a3d09
--- /dev/null
+++ b/core/sourcehook/sourcehook_impl_chookidman.cpp
@@ -0,0 +1,111 @@
+/* ======== SourceHook ========
+* Copyright (C) 2004-2010 Metamod:Source Development Team
+* No warranties of any kind
+*
+* License: zlib/libpng
+*
+* Author(s): Pavol "PM OnoTo" Marko
+* Contributors: Scott "Damaged Soul" Ehlert
+* ============================
+*/
+
+#include "sourcehook_impl.h"
+
+namespace SourceHook
+{
+	namespace Impl
+	{
+		CHookIDManager::CHookIDManager()
+		{
+		}
+
+		int CHookIDManager::New(const CProto &proto, int vtbl_offs, int vtbl_idx, void *vfnptr,
+			void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
+		{
+			Entry tmp(proto, vtbl_offs, vtbl_idx, vfnptr, adjustediface, plug, thisptr_offs, handler, post);
+
+			size_t cursize = m_Entries.size();
+			for (size_t i = 0; i < cursize; ++i)
+			{
+				if (m_Entries[i].isfree)
+				{
+					m_Entries[i] = tmp;
+					return static_cast<int>(i) + 1;
+				}
+			}
+
+			m_Entries.push_back(tmp);
+			return static_cast<int>(m_Entries.size());		// return size() because hookid = id+1 anyway
+		}
+
+		bool CHookIDManager::Remove(int hookid)
+		{
+			int realid = hookid - 1;
+			if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
+				return false;
+
+			m_Entries[realid].isfree = true;
+
+			// :TODO: remove free ids from back sometimes ??
+
+			return true;
+		}
+
+		const CHookIDManager::Entry * CHookIDManager::QueryHook(int hookid)
+		{
+			int realid = hookid - 1;
+			if (realid < 0 || realid >= static_cast<int>(m_Entries.size()) || m_Entries[realid].isfree)
+				return NULL;
+
+			return &m_Entries[realid];
+		}
+
+		void CHookIDManager::FindAllHooks(CVector<int> &output, const CProto &proto, int vtbl_offs,
+			int vtbl_idx, void *adjustediface, Plugin plug, int thisptr_offs, ISHDelegate *handler, bool post)
+		{
+			// oh my god, a lot of parameters...
+			size_t cursize = m_Entries.size();
+			for (size_t i = 0; i < cursize; ++i)
+			{
+				if (!m_Entries[i].isfree && m_Entries[i].proto == proto && m_Entries[i].vtbl_offs == vtbl_offs &&
+					m_Entries[i].vtbl_idx == vtbl_idx && m_Entries[i].adjustediface == adjustediface && m_Entries[i].plug == plug &&
+					m_Entries[i].thisptr_offs == thisptr_offs && m_Entries[i].handler->IsEqual(handler) && m_Entries[i].post == post)
+				{
+					output.push_back(static_cast<int>(i) + 1);
+				}
+			}
+		}
+
+		void CHookIDManager::FindAllHooks(CVector<int> &output)
+		{
+			size_t cursize = m_Entries.size();
+			for (size_t i = 0; i < cursize; ++i)
+			{
+				if (!m_Entries[i].isfree)
+					output.push_back(static_cast<int>(i) + 1);
+			}
+		}
+
+		void CHookIDManager::FindAllHooks(CVector<int> &output, Plugin plug)
+		{
+			size_t cursize = m_Entries.size();
+			for (size_t i = 0; i < cursize; ++i)
+			{
+				if (!m_Entries[i].isfree && m_Entries[i].plug == plug)
+					output.push_back(static_cast<int>(i) + 1);
+			}
+		}
+
+
+		void CHookIDManager::RemoveAll(void *vfnptr)
+		{
+			size_t cursize = m_Entries.size();
+			for (size_t i = 0; i < cursize; ++i)
+			{
+				if (!m_Entries[i].isfree && m_Entries[i].vfnptr == vfnptr)
+					m_Entries[i].isfree = true;
+			}
+		}
+
+	}
+}
diff --git a/core/sourcehook/sourcehook_impl_chookidman.h b/core/sourcehook/sourcehook_impl_chookidman.h
index 20dfeba..03f0bc5 100644
--- a/core/sourcehook/sourcehook_impl_chookidman.h
+++ b/core/sourcehook/sourcehook_impl_chookidman.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_impl_chookmaninfo.cpp b/core/sourcehook/sourcehook_impl_chookmaninfo.cpp
new file mode 100644
index 0000000..639b7a2
--- /dev/null
+++ b/core/sourcehook/sourcehook_impl_chookmaninfo.cpp
@@ -0,0 +1,84 @@
+/* ======== SourceHook ========
+* Copyright (C) 2004-2010 Metamod:Source Development Team
+* No warranties of any kind
+*
+* License: zlib/libpng
+*
+* Author(s): Pavol "PM OnoTo" Marko
+* Contributors: Scott "Damaged Soul" Ehlert
+* ============================
+*/
+
+#include "sourcehook_impl.h"
+
+namespace SourceHook
+{
+	namespace Impl
+	{
+		CHookManager::CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc)
+			: m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc), m_Version(-1)
+		{
+			// Query pubfunc
+			//  -> Should call SetInfo and set all the other variables!
+			if (m_PubFunc(false, this) != 0)
+			{
+				// Error!
+				m_Version = -1;
+			}
+		}
+
+		void CHookManager::SetInfo(int hookman_version, int vtbloffs, int vtblidx,
+			ProtoInfo *proto, void *hookfunc_vfnptr)
+		{
+			m_Version = hookman_version;
+			m_VtblOffs = vtbloffs;
+			m_VtblIdx = vtblidx;
+			m_Proto = proto;
+			m_HookfuncVfnptr = hookfunc_vfnptr;
+		}
+
+		void CHookManager::Register()
+		{
+			m_PubFunc(true, this);
+		}
+
+		void CHookManager::Unregister()
+		{
+			m_PubFunc(true, NULL);
+		}
+
+		void CHookManager::IncrRef(CVfnPtr *pVfnPtr)
+		{
+			m_VfnPtrs.push_back(pVfnPtr);
+			if (m_VfnPtrs.size() == 1)
+				Register();
+		}
+
+		void CHookManager::DecrRef(CVfnPtr *pVfnPtr)
+		{
+			m_VfnPtrs.remove(pVfnPtr);
+			if (m_VfnPtrs.empty())
+				Unregister();
+		}
+
+		CHookManager *CHookManList::GetHookMan(Plugin plug, HookManagerPubFunc pubFunc)
+		{
+			CHookManager hm(plug, pubFunc);
+			return GetHookMan(hm);
+		}
+
+		CHookManager *CHookManList::GetHookMan(CHookManager &hm)
+		{
+			iterator iter = find(hm);
+			if (iter == end())
+			{
+				push_back(hm);
+				return &(back());
+			}
+			else
+			{
+				return &(*iter);
+			}
+		}
+	}
+}
diff --git a/core/sourcehook/sourcehook_impl_chookmaninfo.h b/core/sourcehook/sourcehook_impl_chookmaninfo.h
index 03de9d7..6a805ea 100644
--- a/core/sourcehook/sourcehook_impl_chookmaninfo.h
+++ b/core/sourcehook/sourcehook_impl_chookmaninfo.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -46,7 +46,7 @@ namespace SourceHook
 			};
 
 			// *** Interface ***
-			inline CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc);
+			CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc);
 
 			inline bool operator==(const Descriptor &other) const;
 			inline bool operator==(const CHookManager &other) const;
@@ -60,11 +60,11 @@ namespace SourceHook
 			inline void *GetHookFunc() const;
 			inline HookManagerPubFunc GetPubFunc() const;
 
-			inline void Register();
-			inline void Unregister();
+			void Register();
+			void Unregister();
 
-			inline void IncrRef(CVfnPtr *pVfnPtr);
-			inline void DecrRef(CVfnPtr *pVfnPtr);
+			void IncrRef(CVfnPtr *pVfnPtr);
+			void DecrRef(CVfnPtr *pVfnPtr);
 
 			List<CVfnPtr*> &GetVfnPtrList()
 			{
@@ -79,22 +79,11 @@ namespace SourceHook
 		class CHookManList : public List<CHookManager>
 		{
 		public:
-			inline CHookManager *GetHookMan(Plugin plug, HookManagerPubFunc pubFunc);
-			inline CHookManager *GetHookMan(CHookManager &hm);
+			CHookManager *GetHookMan(Plugin plug, HookManagerPubFunc pubFunc);
+			CHookManager *GetHookMan(CHookManager &hm);
 		};
 
-		// *** Implementation ***
-		inline CHookManager::CHookManager(Plugin ownerPlugin, HookManagerPubFunc pubFunc)
-			: m_OwnerPlugin(ownerPlugin), m_PubFunc(pubFunc), m_Version(-1)
-		{
-			// Query pubfunc
-			//  -> Should call SetInfo and set all the other variables!
-			if (m_PubFunc(false, this) != 0)
-			{
-				// Error!
-				m_Version = -1;
-			}
-		}
+		// *** Implementation **/
 
 		inline CHookManager::operator bool() const
 		{
@@ -147,50 +136,6 @@ namespace SourceHook
 		{
 			return m_PubFunc;
 		}
-
-		inline void CHookManager::Register()
-		{
-			m_PubFunc(true, this);
-		}
-
-		inline void CHookManager::Unregister()
-		{
-			m_PubFunc(true, NULL);
-		}
-
-		inline void CHookManager::IncrRef(CVfnPtr *pVfnPtr)
-		{
-			m_VfnPtrs.push_back(pVfnPtr);
-			if (m_VfnPtrs.size() == 1)
-				Register();
-		}
-
-		inline void CHookManager::DecrRef(CVfnPtr *pVfnPtr)
-		{
-			m_VfnPtrs.remove(pVfnPtr);
-			if (m_VfnPtrs.empty())
-				Unregister();
-		}
-
-		inline CHookManager *CHookManList::GetHookMan(Plugin plug, HookManagerPubFunc pubFunc)
-		{
-			CHookManager hm(plug, pubFunc);
-			return GetHookMan(hm);
-		}
-
-		inline CHookManager *CHookManList::GetHookMan(CHookManager &hm)
-		{
-			iterator iter = find(hm);
-			if (iter == end())
-			{
-				push_back(hm);
-				return &(back());
-			}
-			else
-			{
-				return &(*iter);
-			}
-		}
 	}
 }
 
diff --git a/core/sourcehook/sourcehook_impl_ciface.h b/core/sourcehook/sourcehook_impl_ciface.h
index 7f3c069..978c16a 100644
--- a/core/sourcehook/sourcehook_impl_ciface.h
+++ b/core/sourcehook/sourcehook_impl_ciface.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_impl_cleanuptask.h b/core/sourcehook/sourcehook_impl_cleanuptask.h
new file mode 100644
index 0000000..7f3e0fe
--- /dev/null
+++ b/core/sourcehook/sourcehook_impl_cleanuptask.h
@@ -0,0 +1,29 @@
+/* ======== SourceHook ========
+* Copyright (C) 2004-2010 Metamod:Source Development Team
+* No warranties of any kind
+*
+* License: zlib/libpng
+*
+* Author(s): Pavol "PM OnoTo" Marko
+* ============================
+*/
+
+#ifndef __SOURCEHOOK_IMPL_CLEANUPTASK_H__
+#define __SOURCEHOOK_IMPL_CLEANUPTASK_H__
+
+
+namespace SourceHook
+{
+	namespace Impl
+	{
+		class ICleanupTask
+		{
+		public:
+			virtual void CleanupAndDeleteThis() = 0;
+		};
+	}
+}
+
+// __SOURCEHOOK_IMPL_CLEANUPTASK_H__
+#endif
+
diff --git a/core/sourcehook/sourcehook_impl_cproto.cpp b/core/sourcehook/sourcehook_impl_cproto.cpp
new file mode 100644
index 0000000..ff8af28
--- /dev/null
+++ b/core/sourcehook/sourcehook_impl_cproto.cpp
@@ -0,0 +1,145 @@
+/* ======== SourceHook ========
+* Copyright (C) 2004-2010 Metamod:Source Development Team
+* No warranties of any kind
+*
+* License: zlib/libpng
+*
+* Author(s): Pavol "PM OnoTo" Marko
+* ============================
+*/
+
+#include "sourcehook_impl.h"
+
+namespace SourceHook
+{
+	namespace Impl
+	{
+		void CProto::Fill(const ProtoInfo *pProto)
+		{
+			if (pProto == NULL)
+				m_Version = -1;
+
+			m_ParamsPassInfo.clear();
+
+			if (pProto->paramsPassInfo[0].size == 0)
+			{
+				// Version 1
+				m_Version = 0;
+				m_Convention = pProto->convention;
+				m_NumOfParams = pProto->numOfParams;
+
+				m_RetPassInfo.size = pProto->retPassInfo.size;
+				m_RetPassInfo.type = pProto->retPassInfo.type;
+				m_RetPassInfo.flags = GetRealFlags(pProto->retPassInfo);
+
+				m_RetPassInfo.pNormalCtor = NULL;
+				m_RetPassInfo.pCopyCtor = NULL;
+				m_RetPassInfo.pDtor = NULL;
+				m_RetPassInfo.pAssignOperator = NULL;
+
+				
+				m_ParamsPassInfo.resize(pProto->numOfParams);
+
+				for (int i = 1; i <= pProto->numOfParams; ++i)
+				{
+					m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
+					m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
+					m_ParamsPassInfo[i-1].flags = GetRealFlags(pProto->paramsPassInfo[i]);
+
+					m_ParamsPassInfo[i-1].pNormalCtor = NULL;
+					m_ParamsPassInfo[i-1].pCopyCtor = NULL;
+					m_ParamsPassInfo[i-1].pDtor = NULL;
+					m_ParamsPassInfo[i-1].pAssignOperator = NULL;
+				}
+			}
+			else if (pProto->paramsPassInfo[0].size == 1)
+			{
+				// Version 2
+				m_Version = 1;
+				m_Convention = pProto->convention;
+				m_NumOfParams = pProto->numOfParams;
+
+				m_RetPassInfo.size = pProto->retPassInfo.size;
+				m_RetPassInfo.type = pProto->retPassInfo.type;
+				m_RetPassInfo.flags = pProto->retPassInfo.flags;
+
+				m_RetPassInfo.pNormalCtor = pProto->retPassInfo2.pNormalCtor;
+				m_RetPassInfo.pCopyCtor = pProto->retPassInfo2.pCopyCtor;
+				m_RetPassInfo.pDtor = pProto->retPassInfo2.pDtor;
+				m_RetPassInfo.pAssignOperator = pProto->retPassInfo2.pAssignOperator;
+
+				m_ParamsPassInfo.resize(pProto->numOfParams);
+
+				for (int i = 1; i <= pProto->numOfParams; ++i)
+				{
+					m_ParamsPassInfo[i-1].size = pProto->paramsPassInfo[i].size;
+					m_ParamsPassInfo[i-1].type = pProto->paramsPassInfo[i].type;
+					m_ParamsPassInfo[i-1].flags = pProto->paramsPassInfo[i].flags;
+
+					m_ParamsPassInfo[i-1].pNormalCtor = pProto->paramsPassInfo2[i].pNormalCtor;
+					m_ParamsPassInfo[i-1].pCopyCtor = pProto->paramsPassInfo2[i].pCopyCtor;
+					m_ParamsPassInfo[i-1].pDtor = pProto->paramsPassInfo2[i].pDtor;
+					m_ParamsPassInfo[i-1].pAssignOperator = pProto->paramsPassInfo2[i].pAssignOperator;
+				}
+			}
+			else
+			{
+				// Unknown
+				m_Version = -1;
+			}
+		}
+
+		// Basic compat test
+		// Other than this, we assume that the plugins know what they're doing
+		bool CProto::operator == (const CProto &other) const
+		{
+			if (m_Version < 0 || other.GetVersion() < 0)
+				return false;
+
+			if (m_NumOfParams != other.GetNumOfParams())
+				return false;
+
+			if (m_Convention != ProtoInfo::CallConv_Unknown && other.GetConvention() != ProtoInfo::CallConv_Unknown &&
+				m_Convention != other.GetConvention())
+				return false;
+
+			if (GetRealSize(GetRet()) != GetRealSize(other.GetRet()))
+				return false;
+
+			for (int i = 0; i < m_NumOfParams; ++i)
+			{
+				if (GetRealSize(GetParam(i)) != GetRealSize(other.GetParam(i)))
+					return false;
+				if (GetParam(i).type != PassInfo::PassType_Unknown && other.GetParam(i).type != PassInfo::PassType_Unknown)
+				{
+					if (GetParam(i).type != other.GetParam(i).type)
+						return false;
+					if (GetParam(i).flags != other.GetParam(i).flags)
+						return false;
+				}
+			}
+
+			return true;
+		}
+
+		bool CProto::ExactlyEqual(const CProto &other) const
+		{
+			if (m_Version != other.m_Version ||
+				m_NumOfParams != other.m_NumOfParams ||
+				m_Convention != other.m_Convention ||
+				GetRet() != other.GetRet())
+			{
+				return false;
+			}
+
+			for (int i = 0; i < m_NumOfParams; ++i)
+			{
+				if(GetParam(i) != other.GetParam(i))
+					return false;
+			}
+
+			return true;
+		}
+		
+	}
+}
diff --git a/core/sourcehook/sourcehook_impl_cproto.h b/core/sourcehook/sourcehook_impl_cproto.h
index b11b925..cb436f1 100644
--- a/core/sourcehook/sourcehook_impl_cproto.h
+++ b/core/sourcehook/sourcehook_impl_cproto.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/sourcehook_impl_cvfnptr.cpp b/core/sourcehook/sourcehook_impl_cvfnptr.cpp
new file mode 100644
index 0000000..5159b0c
--- /dev/null
+++ b/core/sourcehook/sourcehook_impl_cvfnptr.cpp
@@ -0,0 +1,253 @@
+/* ======== SourceHook ========
+* Copyright (C) 2004-2010 Metamod:Source Development Team
+* No warranties of any kind
+*
+* License: zlib/libpng
+*
+* Author(s): Pavol "PM OnoTo" Marko
+* ============================
+*/
+
+#include "sourcehook_impl.h"
+
+namespace SourceHook
+{
+	namespace Impl
+	{
+		CPageAlloc CVfnPtr::ms_AlignedPageAllocator(8);
+
+		CVfnPtr::CVfnPtr(void *ptr)
+			: m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(m_Ptr)),
+			m_OrigCallThunk(NULL)
+		{
+		}
+
+		CVfnPtr::~CVfnPtr()
+		{
+			if (!m_HookMans.empty())
+				m_HookMans.front()->DecrRef(this);
+		}
+
+		bool CVfnPtr::Init()
+		{
+			// Initalize the vfn ptr info object.
+
+			// If we're running on GCC and the original vtable entry is odd
+			// we have a problem.
+			// The hook functions use non-virtual member function pointers to
+			// call the original function (see sourcehook.hxx, SH_SETUP_MFP and SH_CALL_ORIG)
+			// GCC has the same format for virtual and non-virtual MFPs:
+			// virtual ones have an odd value as "funcptr" where the offset into the vtable is encoded
+			// non-virtual ones have the direct function pointer as "funcptr", assuming that it is even
+
+			// When m_OrigEntry is odd, GCC's runtime MFP calling code interpretes it as a virtual
+			// function call though we want to call the function in a non-virtual way
+			// (the original function call mechanism between the pre and post hook loop has to bypass
+			// the virtual calling mechanism in order to call the original function).
+
+#if SH_COMP==SH_COMP_GCC
+			if ((((ptrdiff_t)m_OrigEntry) & 1) != 0)
+			{
+				// Odd orig entry.
+				if (SH_PTRSIZE != 4)
+				{
+					// We only have code for IA32 atm!
+					return false;
+				}
+
+				// Generate a new thunk
+				m_OrigCallThunk = ms_AlignedPageAllocator.Alloc(5);
+				ms_AlignedPageAllocator.SetRW(m_OrigCallThunk);
+
+				unsigned char* thunkBase = reinterpret_cast<unsigned char*>(m_OrigCallThunk);
+				*(thunkBase + 0) = 0xE9;		// offset jump, immediate operand
+				ptrdiff_t *offsetAddr = reinterpret_cast<ptrdiff_t*>(thunkBase + 1);
+				
+				// destination = src + offset + 5
+				// <=>  offset = destination - src - 5
+				*offsetAddr =
+					(reinterpret_cast<unsigned char*>(m_OrigEntry) - thunkBase) - 5;
+
+				ms_AlignedPageAllocator.SetRE(m_OrigCallThunk);
+			}
+#endif
+			return true;
+		}
+
+		class CVfnPtrOrigThunkCleanup : public ICleanupTask
+		{
+			CPageAlloc *m_Allocator;
+			void *m_AddrToFree;
+
+		public:
+			CVfnPtrOrigThunkCleanup(CPageAlloc *allocator, void *addrToFree) :
+				m_Allocator(allocator), m_AddrToFree(addrToFree)
+			{
+			}
+
+			virtual void CleanupAndDeleteThis()
+			{
+				m_Allocator->Free(m_AddrToFree);
+				delete this;
+			}
+		};
+
+		ICleanupTask* CVfnPtr::GetCleanupTask()
+		{
+			if (m_OrigCallThunk != NULL)
+			{
+				return new CVfnPtrOrigThunkCleanup(&ms_AlignedPageAllocator, m_OrigCallThunk);
+			}
+			else
+			{
+				return NULL;
+			}
+		}
+
+		void* CVfnPtr::GetOrigCallAddr() const
+		{
+			if (m_OrigCallThunk)
+			{
+				return m_OrigCallThunk;
+			}
+			else
+			{
+				return m_OrigEntry;
+			}
+		}
+
+		bool CVfnPtr::Revert()
+		{
+			// Only patch the vfnptr back if the module is still in memory
+			// If it's not, do not remove stuff like we did before
+			// First off we did it wrong (shutdown the whole hookman, uh..) and secondly applications may be
+			// confused by RemoveHook returning false then (yeah, I know, I made this one up, no one checks for RemoveHook error)
+			if (ModuleInMemory(reinterpret_cast<char*>(m_Ptr), SH_PTRSIZE))
+			{
+				return Patch(m_OrigEntry);
+			}
+			else
+			{
+				return true;
+			}
+		}
+
+		CIface *CVfnPtr::FindIface(void *iface)
+		{
+			List<CIface>::iterator iter = m_IfaceList.find(iface);
+			if (iter == m_IfaceList.end())
+				return NULL;
+			else
+				return &(*iter);
+		}
+
+		void CVfnPtr::AddHookMan(CHookManager *pHookMan)
+		{
+			List<CHookManager*>::iterator iter;
+
+			// Don't accept invalid hook managers
+			if (!*pHookMan)
+				return;
+
+			// Check whether this hook manager already exists; if yes, ignore.
+			iter = m_HookMans.find(pHookMan);
+			if (iter != m_HookMans.end())
+				return;
+
+			// It doesn't -> add it. Add it to the end of its version group.
+			for (iter = m_HookMans.begin(); iter != m_HookMans.end(); ++iter)
+			{
+				if ((*iter)->GetVersion() < pHookMan->GetVersion())
+					break;
+			}
+
+			bool isBeginning = iter == m_HookMans.begin();
+
+			m_HookMans.insert(iter, pHookMan);
+
+			if (isBeginning)
+			{
+				pHookMan->IncrRef(this);
+				if (m_HookMans.size() > 1)
+				{
+					// If another hookman was used until now but this one is better
+					// (which it is because it's the first -> it has a higher version)
+					// -> switch!
+
+					List<CHookManager*>::iterator second = m_HookMans.begin();
+					++second;
+
+					(*second)->DecrRef(this);
+				}
+
+				// Make sure that this vfnptr points at it
+				Patch(pHookMan->GetHookFunc());
+			}
+		}
+
+		bool CVfnPtr::HookManRemoved(CHookManager *pHookMan)
+		{
+			// Don't accept invalid hook managers
+			if (!*pHookMan)
+				return true;
+
+			List<CHookManager*>::iterator iter = m_HookMans.find(pHookMan);
+			if (iter == m_HookMans.end())
+				return true;							// Didn't exist here anyway
+
+			if (iter == m_HookMans.begin())
+			{
+				// It is the first one!
+				pHookMan->DecrRef(this);
+				m_HookMans.erase(iter);
+
+				if (m_HookMans.empty())
+					return false;				// No more hookmans -> let SH delete us
+
+				// Activate second -> now first hookman
+				m_HookMans.front()->IncrRef(this);
+				Patch(m_HookMans.front()->GetHookFunc());
+			}
+			else
+			{
+				m_HookMans.erase(iter);
+			}
+			return true;
+		}
+
+		bool CVfnPtr::Patch(void *newValue)
+		{
+			if (!SetMemAccess(m_Ptr, sizeof(void*), SH_MEM_READ | SH_MEM_WRITE))
+			{
+				return false;
+			}
+
+			*reinterpret_cast<void**>(m_Ptr) = newValue;
+
+			return true;
+		}
+
+		CIface &CVfnPtr::GetIface(void *iface)
+		{
+			List<CIface>::iterator iter = m_IfaceList.find(iface);
+			if (iter == m_IfaceList.end())
+			{
+				CIface newIface(iface);
+				if (iface == NULL)
+				{
+					m_IfaceList.push_front(newIface);
+					return m_IfaceList.front();
+				}
+				else
+				{
+					m_IfaceList.push_back(newIface);
+					return m_IfaceList.back();
+				}
+			}
+			else
+			{
+				return *iter;
+			}
+		}
+	}
+}
diff --git a/core/sourcehook/sourcehook_impl_cvfnptr.h b/core/sourcehook/sourcehook_impl_cvfnptr.h
index edb1c7c..1575728 100644
--- a/core/sourcehook/sourcehook_impl_cvfnptr.h
+++ b/core/sourcehook/sourcehook_impl_cvfnptr.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
@@ -13,6 +13,8 @@
 
 #include "sh_list.h"
 #include "sh_memory.h"
+#include "sh_pagealloc.h"
+#include "sourcehook_impl_cleanuptask.h"
 
 namespace SourceHook
 {
@@ -20,9 +22,12 @@ namespace SourceHook
 	{
 		class CVfnPtr
 		{
+			static CPageAlloc ms_AlignedPageAllocator;
+
 			// *** Data ***
 			void *m_Ptr;
 			void *m_OrigEntry;
+			void *m_OrigCallThunk;		// See Init() method
 
 			List<CHookManager*> m_HookMans;
 			List<CIface> m_IfaceList;
@@ -31,17 +36,21 @@ namespace SourceHook
 			typedef void* Descriptor;
 
 			// *** Interface ***
-			inline CVfnPtr(void *ptr);
-			inline ~CVfnPtr();
+			CVfnPtr(void *ptr);
+			~CVfnPtr();
+			bool Init();
 			inline bool operator==(const Descriptor &other);
 			inline void *GetPtr() const;
 			inline void *GetOrigEntry() const;
+			void *GetOrigCallAddr() const;
 			inline List<CIface> &GetIfaceList();
 			inline const List<CIface> &GetIfaceList() const;
-			inline CIface *FindIface(void *iface);
+			CIface *FindIface(void *iface);
 			CIface &GetIface(void *iface);
 			bool Patch(void *newValue);
-			inline bool Revert();
+			bool Revert();
+
+			ICleanupTask *GetCleanupTask();
 
 			void AddHookMan(CHookManager *pHookMan);
 			// If this returns false, it means that there is no hook manager left
@@ -50,16 +59,6 @@ namespace SourceHook
 		};
 
 		// *** Implementation ***
-		inline CVfnPtr::CVfnPtr(void *ptr)
-			: m_Ptr(ptr), m_OrigEntry(*reinterpret_cast<void**>(m_Ptr))
-		{
-		}
-
-		inline CVfnPtr::~CVfnPtr()
-		{
-			if (!m_HookMans.empty())
-				m_HookMans.front()->DecrRef(this);
-		}
 
 		inline bool CVfnPtr::operator==(const Descriptor &other)
 		{
@@ -85,31 +84,6 @@ namespace SourceHook
 		{
 			return m_IfaceList;
 		}
-
-		inline bool CVfnPtr::Revert()
-		{
-			// Only patch the vfnptr back if the module is still in memory
-			// If it's not, do not remove stuff like we did before
-			// First off we did it wrong (shutdown the whole hookman, uh..) and secondly applications may be
-			// confused by RemoveHook returning false then (yeah, I know, I made this one up, no one checks for RemoveHook error)
-			if (ModuleInMemory(reinterpret_cast<char*>(m_Ptr), SH_PTRSIZE))
-			{
-				return Patch(m_OrigEntry);
-			}
-			else
-			{
-				return true;
-			}
-		}
-
-		inline CIface *CVfnPtr::FindIface(void *iface)
-		{
-			List<CIface>::iterator iter = m_IfaceList.find(iface);
-			if (iter == m_IfaceList.end())
-				return NULL;
-			else
-				return &(*iter);
-		}
 	}
 }
 
diff --git a/core/sourcehook/sourcehook_pibuilder.h b/core/sourcehook/sourcehook_pibuilder.h
index df9e7a5..7b88c00 100644
--- a/core/sourcehook/sourcehook_pibuilder.h
+++ b/core/sourcehook/sourcehook_pibuilder.h
@@ -1,5 +1,5 @@
 /* ======== SourceHook ========
-* Copyright (C) 2004-2008 Metamod:Source Development Team
+* Copyright (C) 2004-2010 Metamod:Source Development Team
 * No warranties of any kind
 *
 * License: zlib/libpng
diff --git a/core/sourcehook/test/Makefile b/core/sourcehook/test/Makefile
index e85f092..d5d4c39 100644
--- a/core/sourcehook/test/Makefile
+++ b/core/sourcehook/test/Makefile
@@ -9,8 +9,8 @@ INCLUDE = -I. -I..
 MAX_PARAMS=20
 
 BINARY = sourcehook_test
-OBJECTS = main.cpp sourcehook.cpp sourcehook_hookmangen.cpp $(shell ls -t test*.cpp)
-HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h
+OBJECTS = main.cpp sourcehook.cpp sourcehook_hookmangen.cpp sourcehook_impl_chookmaninfo.cpp sourcehook_impl_chookidman.cpp sourcehook_impl_cproto.cpp sourcehook_impl_cvfnptr.cpp $(shell ls -t test*.cpp)
+HEADERS = ../sh_list.h ../sh_tinyhash.h ../sh_memory.h ../sh_string.h ../sh_vector.h ../sourcehook_impl.h ../FastDelegate.h ../sourcehook.h ../sh_memfuncinfo.h ../sh_pagealloc.h
 
 ifeq "$(DEBUG)" "true"
 	BIN_DIR = Debug
@@ -48,10 +48,18 @@ all:
 	mkdir -p $(BIN_DIR)
 	ln -sf ../sourcehook.cpp
 	ln -sf ../sourcehook_hookmangen.cpp
+	ln -sf ../sourcehook_impl_chookidman.cpp
+	ln -sf ../sourcehook_impl_chookmaninfo.cpp
+	ln -sf ../sourcehook_impl_cproto.cpp
+	ln -sf ../sourcehook_impl_cvfnptr.cpp
 	$(MAKE) $(BINARY)
 	rm -f $(BINARY)
 	rm -f sourcehook.cpp
 	rm -f sourcehook_hookmangen.cpp
+	rm -f sourcehook_impl_chookidman.cpp
+	rm -f sourcehook_impl_chookmaninfo.cpp
+	rm -f sourcehook_impl_cproto.cpp
+	rm -f sourcehook_impl_cvfnptr.cpp
 	ln -sf $(BIN_DIR)/$(BINARY) $(BINARY)
 
 
diff --git a/core/sourcehook/test/main.cpp b/core/sourcehook/test/main.cpp
index 9b2ba82..dc1fb88 100644
--- a/core/sourcehook/test/main.cpp
+++ b/core/sourcehook/test/main.cpp
@@ -49,6 +49,7 @@ DECL_TEST(RefRet);
 DECL_TEST(VPHooks);
 DECL_TEST(CPageAlloc);					// in testhookmangen.cpp
 DECL_TEST(HookManGen);
+DECL_TEST(OddThunks);
 
 int main(int argc, char *argv[])
 {
@@ -73,6 +74,7 @@ int main(int argc, char *argv[])
 	DO_TEST(VPHooks);
 	DO_TEST(CPageAlloc);
 	DO_TEST(HookManGen);
+	DO_TEST(OddThunks);
 
 	cout << endl << "----" << endl << "Passed: " << passed << endl << "Failed: " << failed << endl;
 	cout << "Total: " << passed + failed << endl;
diff --git a/core/sourcehook/test/test.sln b/core/sourcehook/test/test.sln
new file mode 100644
index 0000000..327a99a
--- /dev/null
+++ b/core/sourcehook/test/test.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{456BBA64-FF14-4292-8443-3BA79E4D84CC}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug_NoDebugRuntimeLib|Win32 = Debug_NoDebugRuntimeLib|Win32
+		Debug|Win32 = Debug|Win32
+		DebugOpt|Win32 = DebugOpt|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.ActiveCfg = Debug_NoDebugRuntimeLib|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug_NoDebugRuntimeLib|Win32.Build.0 = Debug_NoDebugRuntimeLib|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.ActiveCfg = Debug|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Debug|Win32.Build.0 = Debug|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.ActiveCfg = DebugOpt|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.DebugOpt|Win32.Build.0 = DebugOpt|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.ActiveCfg = Release|Win32
+		{456BBA64-FF14-4292-8443-3BA79E4D84CC}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/core/sourcehook/test/test.vcproj b/core/sourcehook/test/test.vcproj
new file mode 100644
index 0000000..4e937b6
--- /dev/null
+++ b/core/sourcehook/test/test.vcproj
@@ -0,0 +1,619 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="9,00"
+	Name="test"
+	ProjectGUID="{456BBA64-FF14-4292-8443-3BA79E4D84CC}"
+	RootNamespace="test"
+	Keyword="Win32Proj"
+	TargetFrameworkVersion="131072"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				FavorSizeOrSpeed="0"
+				AdditionalIncludeDirectories="../..;.."
+				PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;SH_DEBUG;_CRT_SECURE_NO_DEPRECATE"
+				StringPooling="true"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				EnableFunctionLevelLinking="true"
+				RuntimeTypeInfo="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/test.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/test.pdb"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="3"
+				InlineFunctionExpansion="1"
+				FavorSizeOrSpeed="2"
+				OmitFramePointers="true"
+				AdditionalIncludeDirectories="../..;.."
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+				StringPooling="true"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				RuntimeTypeInfo="true"
+				UsePrecompiledHeader="0"
+				BrowseInformation="0"
+				WarningLevel="3"
+				SuppressStartupBanner="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/test.exe"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				GenerateMapFile="true"
+				MapExports="true"
+				SubSystem="1"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="DebugOpt|Win32"
+			OutputDirectory="DebugOpt"
+			IntermediateDirectory="DebugOpt"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="3"
+				InlineFunctionExpansion="1"
+				EnableIntrinsicFunctions="false"
+				FavorSizeOrSpeed="2"
+				OmitFramePointers="true"
+				AdditionalIncludeDirectories=".."
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+				StringPooling="true"
+				MinimalRebuild="false"
+				BasicRuntimeChecks="0"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				RuntimeTypeInfo="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/test.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/test.pdb"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Debug_NoDebugRuntimeLib|Win32"
+			OutputDirectory="Debug_NoDebugRuntimeLib"
+			IntermediateDirectory="Debug_NoDebugRuntimeLib"
+			ConfigurationType="1"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				FavorSizeOrSpeed="0"
+				AdditionalIncludeDirectories="../..;.."
+				PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_DEPRECATE"
+				StringPooling="true"
+				MinimalRebuild="true"
+				ExceptionHandling="1"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="0"
+				EnableFunctionLevelLinking="true"
+				RuntimeTypeInfo="true"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="$(OutDir)/test.exe"
+				LinkIncremental="2"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/test.pdb"
+				SubSystem="1"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
+			>
+			<Filter
+				Name="SourceHook"
+				>
+				<File
+					RelativePath="..\..\sourcehook.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_hookmangen.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_chookidman.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_chookmaninfo.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_cproto.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_cvfnptr.cpp"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="TestTools"
+				>
+				<File
+					RelativePath="..\main.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\test1.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\test2.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\test3.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\test4.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testbail.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testbail2.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testhookmangen.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testlist.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testmanual.cpp"
+					>
+					<FileConfiguration
+						Name="Release|Win32"
+						>
+						<Tool
+							Name="VCCLCompilerTool"
+							GeneratePreprocessedFile="0"
+						/>
+					</FileConfiguration>
+				</File>
+				<File
+					RelativePath="..\testmulti.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testoddthunks.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testrecall.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testreentr.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testref.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testrefret.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\testvphooks.cpp"
+					>
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc"
+			>
+			<Filter
+				Name="TestTools"
+				>
+				<File
+					RelativePath="..\testbail.h"
+					>
+				</File>
+				<File
+					RelativePath="..\testevents.h"
+					>
+				</File>
+				<File
+					RelativePath="..\testhookmangen.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="SourceHook"
+				>
+				<File
+					RelativePath="..\..\sh_list.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_memfuncinfo.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_memory.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_pagealloc.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_stack.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_string.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_tinyhash.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sh_vector.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_hookmangen.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_hookmangen_x86.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_chook.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_chookidman.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_chookmaninfo.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_ciface.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_cleanuptask.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_cproto.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_impl_cvfnptr.h"
+					>
+				</File>
+				<File
+					RelativePath="..\..\sourcehook_pibuilder.h"
+					>
+				</File>
+				<File
+					RelativePath="..\sourcehook_test.h"
+					>
+				</File>
+				<Filter
+					Name="generate"
+					>
+					<File
+						RelativePath="..\..\generate\FastDelegate.hxx"
+						>
+					</File>
+					<File
+						RelativePath="..\..\generate\sh_memfuncinfo.hxx"
+						>
+					</File>
+					<File
+						RelativePath="..\..\generate\sourcehook.hxx"
+						>
+						<FileConfiguration
+							Name="Debug_NoDebugRuntimeLib|Win32"
+							>
+							<Tool
+								Name="VCCustomBuildTool"
+								CommandLine="echo on&#x0D;&#x0A;pushd ..\..\generate&#x0D;&#x0A;shworker.exe iter sourcehook.hxx sourcehook.h 16&#x0D;&#x0A;copy sourcehook.h ..\sourcehook.h&#x0D;&#x0A;popd&#x0D;&#x0A;"
+								Outputs="..\..\sourcehook.h"
+							/>
+						</FileConfiguration>
+					</File>
+					<File
+						RelativePath="..\testhookmangen.hxx"
+						>
+					</File>
+				</Filter>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/core/sourcehook/test/testoddthunks.cpp b/core/sourcehook/test/testoddthunks.cpp
new file mode 100644
index 0000000..c0e3917
--- /dev/null
+++ b/core/sourcehook/test/testoddthunks.cpp
@@ -0,0 +1,163 @@
+#include <string>
+#include "sourcehook_test.h"
+#include "sh_pagealloc.h"
+#include "testevents.h"
+
+namespace
+{
+	StateList g_States;
+	SourceHook::ISourceHook *g_SHPtr;
+	SourceHook::Plugin g_PLID;
+
+	MAKE_STATE(State_Func_Called);
+	MAKE_STATE(State_Pre1_Called);
+	MAKE_STATE(State_Pre2_Called);
+
+	int g_CallNumber;
+
+	class Test
+	{
+	public:
+		virtual void Func()
+		{
+			ADD_STATE(State_Func_Called);
+		}
+	};
+
+	Test *g_pInst;
+
+	void Handler_Func_Pre1()
+	{
+		ADD_STATE(State_Pre1_Called);
+	}
+
+	SH_DECL_HOOK0_void(Test, Func, SH_NOATTRIB, 0);
+
+	void Handler_Func_Pre2()
+	{
+		ADD_STATE(State_Pre2_Called);
+
+		++g_CallNumber;
+		if (g_CallNumber == 2)
+		{
+			// REMOVE ourselves
+			SH_REMOVE_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre1), false);
+			SH_REMOVE_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre2), false);
+		}
+
+		// Call again.
+		g_pInst->Func();
+	}
+
+	Test *MyInstanceFactory()
+	{
+		return new Test;
+	}
+
+	SourceHook::CPageAlloc g_ThunkAllocator(2);
+	void *g_OddThunkMemory = NULL;
+	void *g_OddThunk = NULL;
+
+	// Guarantees that Func()
+	// has a vtable entry showing to an ODD address
+	void PatchFuncWithOddThunk()
+	{
+		g_OddThunkMemory = g_ThunkAllocator.Alloc(10);
+		unsigned char* base = reinterpret_cast<unsigned char*>(g_OddThunkMemory);
+
+		if (((ptrdiff_t)base) & 1)
+		{
+			// ODD, ok.
+		}
+		else
+		{
+			// EVEN. make odd.
+			base += 1;
+		}
+
+		// Get vtable entry pointer
+		SourceHook::MemFuncInfo info = {true, -1, 0, 0};
+		SourceHook::GetFuncInfo(g_pInst, &Test::Func, info);
+
+		void *adjustediface = NULL;
+		void **cur_vtptr = NULL;
+		void **cur_vfnptr = NULL;
+
+		adjustediface = reinterpret_cast<void*>(reinterpret_cast<char*>(g_pInst) + info.thisptroffs);
+
+		cur_vtptr = *reinterpret_cast<void***>(
+			reinterpret_cast<char*>(adjustediface) + info.vtbloffs);
+		cur_vfnptr = reinterpret_cast<void**>(cur_vtptr + info.vtblindex);
+
+		
+		// Original function
+		void *origEntry = *cur_vfnptr;
+
+		// Now generate the jump code
+		g_ThunkAllocator.SetRW(g_OddThunkMemory);
+
+		*(base + 0) = 0xE9;		// offset jump, immediate operand
+		ptrdiff_t *offsetAddr = reinterpret_cast<ptrdiff_t*>(base + 1);
+				
+		// destination = src + offset + 5
+		// <=>  offset = destination - src - 5
+		*offsetAddr =
+			(reinterpret_cast<unsigned char*>(origEntry) - base) - 5;
+
+		g_ThunkAllocator.SetRE(g_OddThunkMemory);
+		
+		g_OddThunk = reinterpret_cast<void*>(base);
+
+		// Now set the odd thunk as new vtable entry
+		SourceHook::SetMemAccess((void*)cur_vfnptr, sizeof(void*), SH_MEM_READ | SH_MEM_WRITE);
+		*cur_vfnptr = g_OddThunk;
+	}
+
+	void FreeOddThunk()
+	{
+		g_ThunkAllocator.Free(g_OddThunkMemory);
+		g_OddThunk = NULL;
+	}
+}
+
+bool TestOddThunks(std::string &error)
+{
+	GET_SHPTR(g_SHPtr);
+	g_PLID = 1337;
+
+	g_CallNumber = 0;
+
+	g_pInst = MyInstanceFactory();
+
+	PatchFuncWithOddThunk();
+
+	SH_ADD_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre1), false);
+	SH_ADD_HOOK(Test, Func, g_pInst, SH_STATIC(Handler_Func_Pre2), false);
+
+	g_pInst->Func();
+
+	CHECK_STATES((&g_States,
+		// FIRST func() call
+		new State_Pre1_Called(),
+		new State_Pre2_Called(),		// calls Func() again
+
+		// SECOND func() call
+		new State_Pre1_Called(),
+		new State_Pre2_Called(),		// removes hooks and calls Func() again
+
+		// THIRD func() call
+		new State_Func_Called(),
+
+		// SECOND func() call
+		new State_Func_Called(),
+
+		// FIRST func() call
+		new State_Func_Called(),
+		NULL), "Part 1");
+
+	delete g_pInst;
+	FreeOddThunk();
+
+	return true;
+}
+
diff --git a/core/sourcehook/test/testrefret.cpp b/core/sourcehook/test/testrefret.cpp
index 597c0bd..f47c0df 100644
--- a/core/sourcehook/test/testrefret.cpp
+++ b/core/sourcehook/test/testrefret.cpp
@@ -49,6 +49,11 @@ namespace
 		}
 	};
 
+	SH_DECL_HOOK0(Test, Func1, SH_NOATTRIB, 0, int&);
+	SH_DECL_MANUALHOOK0(Manual_Test_Func1, 0, 0, 0, int&);
+	SH_DECL_HOOK1(Test, Func2, SH_NOATTRIB, 0, const int&, int);
+	SH_DECL_MANUALHOOK1(Manual_Test_Func2, 1, 0, 0, const int&, int);
+
 	class CHook
 	{
 	public:
@@ -76,12 +81,18 @@ namespace
 			RETURN_META_VALUE(MRES_OVERRIDE, m_Var);
 		}
 
-		virtual const int& Func2_Pre1(int p1)
+		virtual const int& Func2_PreRecall_OverrideRet_Normal(int p1)
 		{
 			ADD_STATE(State_Func2_Pre1(p1, &m_Var));
 			RETURN_META_VALUE_NEWPARAMS(MRES_OVERRIDE, m_Var, static_cast<const int& (Test::*)(int)>(&Test::Func2), (1337));
 		}
 
+		virtual const int& Func2_PreRecall_OverrideRet_Manual(int p1)
+		{
+			ADD_STATE(State_Func2_Pre1(p1, &m_Var));
+			RETURN_META_VALUE_MNEWPARAMS(MRES_OVERRIDE, m_Var, Manual_Test_Func2, (1337));
+		}
+
 		virtual const int& Func2_Post1(int p1)
 		{
 			ADD_STATE(State_Func2_Post1(p1, &META_RESULT_ORIG_RET(int&), &META_RESULT_OVERRIDE_RET(int&)));
@@ -89,117 +100,220 @@ namespace
 		}
 	};
 
-	SH_DECL_HOOK0(Test, Func1, SH_NOATTRIB, 0, int&);
-	SH_DECL_HOOK1(Test, Func2, SH_NOATTRIB, 0, const int&, int);
-
 	Test *MyTestFactory()
 	{
 		return new Test;
 	}
 }
 
-bool TestRefRet(std::string &error)
+class TesterRefRet
 {
-	GET_SHPTR(g_SHPtr);
-	g_PLID = 1;
-
-	Test *pTest = MyTestFactory();
-	CAutoPtrDestruction<Test> apd(pTest);
+public:
+	Test *pTest;
 	CHook hook;
 
-	int &ret1 = pTest->Func1();
-	ADD_STATE(State_Func1_Ret(&ret1));
+	TesterRefRet()
+	{
+		pTest = NULL;
+	}
 
-	CHECK_STATES((&g_States,
-		new State_Func1(&pTest->m_Var1),
-		new State_Func1_Ret(&pTest->m_Var1),
-		NULL), "Part 1");
+	bool doTests(std::string &error)
+	{
+		GET_SHPTR(g_SHPtr);
+		g_PLID = 1;
 
-	// Now add Func1_Pre1, which supercedes and returns hook.m_Var
-	SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
+		pTest = MyTestFactory();
+		CAutoPtrDestruction<Test> apd(pTest);
 
-	int &ret2 = pTest->Func1();
-	ADD_STATE(State_Func1_Ret(&ret2));
-	
-	CHECK_STATES((&g_States,
-		new State_Func1_Pre1(&hook.m_Var),		// Pre1 says that it's going to override with hook.m_Var
-		new State_Func1(&pTest->m_Var1),			// Function says that it's going to return pTest->m_Var1
-		new State_Func1_Ret(&hook.m_Var),		// hook.m_Var is returned
-		NULL), "Part 2");
+		int &ret1 = pTest->Func1();
+		ADD_STATE(State_Func1_Ret(&ret1));
 
-	// Now add Func1_Post1, which only reports orig ret and override ret
-	SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
+		CHECK_STATES((&g_States,
+			new State_Func1(&pTest->m_Var1),
+			new State_Func1_Ret(&pTest->m_Var1),
+			NULL), "Part 1");
 
-	int &ret3 = pTest->Func1();
-	ADD_STATE(State_Func1_Ret(&ret3));
-	
-	CHECK_STATES((&g_States,
-		new State_Func1_Pre1(&hook.m_Var),		// Pre1 says that it's going to override with hook.m_Var
-		new State_Func1(&pTest->m_Var1),			// Function says that it's going to return pTest->m_Var1
-		new State_Func1_Post1(&pTest->m_Var1, &hook.m_Var),	// origret(=p1) is what it wanted to
-															// return, overrideret(=p2) is pre1's var
-		new State_Func1_Ret(&hook.m_Var),		// hook.m_Var is returned
-		NULL), "Part 3");
+		// Now add Func1_Pre1, which supercedes and returns hook.m_Var
+		AddHook__Test_Func1__Func1_Pre();
 
-	// Now add Func1_Pre2, which supercedes and returns g_Var (it also sets the override ret from pre1 to 1337)
-	// and add Func1_Post2, which overrides and returns hook.m_Var again.
+		int &ret2 = pTest->Func1();
+		ADD_STATE(State_Func1_Ret(&ret2));
+		
+		CHECK_STATES((&g_States,
+			new State_Func1_Pre1(&hook.m_Var),		// Pre1 says that it's going to override with hook.m_Var
+			new State_Func1(&pTest->m_Var1),			// Function says that it's going to return pTest->m_Var1
+			new State_Func1_Ret(&hook.m_Var),		// hook.m_Var is returned
+			NULL), "Part 2");
 
-	SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
-	SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
+		// Now add Func1_Post1, which only reports orig ret and override ret
+		AddHook__Test_Func1__Func1_Post();
 
-	int &ret4 = pTest->Func1();
-	ADD_STATE(State_Func1_Ret(&ret4));
+		int &ret3 = pTest->Func1();
+		ADD_STATE(State_Func1_Ret(&ret3));
+		
+		CHECK_STATES((&g_States,
+			new State_Func1_Pre1(&hook.m_Var),		// Pre1 says that it's going to override with hook.m_Var
+			new State_Func1(&pTest->m_Var1),			// Function says that it's going to return pTest->m_Var1
+			new State_Func1_Post1(&pTest->m_Var1, &hook.m_Var),	// origret(=p1) is what it wanted to
+																// return, overrideret(=p2) is pre1's var
+			new State_Func1_Ret(&hook.m_Var),		// hook.m_Var is returned
+			NULL), "Part 3");
 
-	CHECK_STATES((&g_States,
-		new State_Func1_Pre1(&hook.m_Var),		// Pre1 says that it's going to override with hook.m_Var
-		new State_Func1_Pre2(MRES_OVERRIDE,			// current status
-							&hook.m_Var,			// override ret (which it set to 1337)
-							&g_Var),				// what it's going to ret, AND supercede with
+		// Now add Func1_Pre2, which supercedes and returns g_Var (it also sets the override ret from pre1 to 1337)
+		// and add Func1_Post2, which overrides and returns hook.m_Var again.
 
-		new State_Func1_Post1(&g_Var, &g_Var),	// origret(=p1) is what pre2 superceded with,
-												//  so  overrideret(=p2) has to be the same
-		new State_Func1_Post2(&hook.m_Var),			// post2 is going to override with hook.m_Var again
-		new State_Func1_Ret(&hook.m_Var),		// ==>>> hook.m_Var is returned
-		NULL), "Part 4");
+		AddHook__Test_Func1__Func1_Pre2();
+		AddHook__Test_Func1__Func1_Post2();
 
-	CHECK_COND(hook.m_Var == 1337, "Part 4.1");
-	
-	// Through a callclass
-	SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(pTest);
-	int &ret5 = SH_CALL(cc1, &Test::Func1)();
-	ADD_STATE(State_Func1_Ret(&ret5));
+		int &ret4 = pTest->Func1();
+		ADD_STATE(State_Func1_Ret(&ret4));
 
-	CHECK_STATES((&g_States,
-		new State_Func1(&pTest->m_Var1),
-		new State_Func1_Ret(&pTest->m_Var1),
-		NULL), "Part 5");
+		CHECK_STATES((&g_States,
+			new State_Func1_Pre1(&hook.m_Var),		// Pre1 says that it's going to override with hook.m_Var
+			new State_Func1_Pre2(MRES_OVERRIDE,			// current status
+								&hook.m_Var,			// override ret (which it set to 1337)
+								&g_Var),				// what it's going to ret, AND supercede with
 
-	SH_RELEASE_CALLCLASS(cc1);
+			new State_Func1_Post1(&g_Var, &g_Var),	// origret(=p1) is what pre2 superceded with,
+													//  so  overrideret(=p2) has to be the same
+			new State_Func1_Post2(&hook.m_Var),			// post2 is going to override with hook.m_Var again
+			new State_Func1_Ret(&hook.m_Var),		// ==>>> hook.m_Var is returned
+			NULL), "Part 4");
 
-	////////////////////////////////////////////////////////////////////////////////////////
-	// Func2 tests
-	const int &ret21 = pTest->Func2(500);
-	ADD_STATE(State_Func2_Ret(&ret21));
+		CHECK_COND(hook.m_Var == 1337, "Part 4.1");
+		
+		// Through a callclass
+		SourceHook::CallClass<Test> *cc1 = SH_GET_CALLCLASS(pTest);
+		int &ret5 = SH_CALL(cc1, &Test::Func1)();
+		ADD_STATE(State_Func1_Ret(&ret5));
 
-	CHECK_STATES((&g_States,
-		new State_Func2(500, &pTest->m_Var2),
-		new State_Func2_Ret(&pTest->m_Var2),
-		NULL), "Part 6");
+		CHECK_STATES((&g_States,
+			new State_Func1(&pTest->m_Var1),
+			new State_Func1_Ret(&pTest->m_Var1),
+			NULL), "Part 5");
 
-	SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Pre1), false);
-	SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
+		SH_RELEASE_CALLCLASS(cc1);
 
-	const int &ret22 = pTest->Func2(500);
-	ADD_STATE(State_Func2_Ret(&ret22));
+		////////////////////////////////////////////////////////////////////////////////////////
+		// Func2 tests
+		const int &ret21 = pTest->Func2(500);
+		ADD_STATE(State_Func2_Ret(&ret21));
 
-	CHECK_STATES((&g_States,
-		new State_Func2_Pre1(500, &hook.m_Var),		// p1 was 500; it's going to override with hook.m_Var; and also change p1 to 1337
-		new State_Func2(1337, &pTest->m_Var2),		// p1 was 1337; it's going to ret pTest->m_Var2
-		new State_Func2_Post1(1337,					// p1 was 1337
-			&pTest->m_Var2,							// orig ret was pTest->m_Var2
-			&hook.m_Var),							// override ret was hook.m_Var
-		new State_Func2_Ret(&hook.m_Var),			// really returned hook.m_Var
-		NULL), "Part 7");
-	
-   	return true;
+		CHECK_STATES((&g_States,
+			new State_Func2(500, &pTest->m_Var2),
+			new State_Func2_Ret(&pTest->m_Var2),
+			NULL), "Part 6");
+
+		AddHook__Test_Func2__Func2_Pre1();
+		AddHook__Test_Func2__Func2_Post1();
+
+		const int &ret22 = pTest->Func2(500);
+		ADD_STATE(State_Func2_Ret(&ret22));
+
+		CHECK_STATES((&g_States,
+			new State_Func2_Pre1(500, &hook.m_Var),		// p1 was 500; it's going to override with hook.m_Var; and also change p1 to 1337
+			new State_Func2(1337, &pTest->m_Var2),		// p1 was 1337; it's going to ret pTest->m_Var2
+			new State_Func2_Post1(1337,					// p1 was 1337
+				&pTest->m_Var2,							// orig ret was pTest->m_Var2
+				&hook.m_Var),							// override ret was hook.m_Var
+			new State_Func2_Ret(&hook.m_Var),			// really returned hook.m_Var
+			NULL), "Part 7");
+		
+   		return true;
+	}
+
+	virtual void AddHook__Test_Func1__Func1_Pre() = 0;
+	virtual void AddHook__Test_Func1__Func1_Post() = 0;
+
+	virtual void AddHook__Test_Func1__Func1_Pre2() = 0;
+	virtual void AddHook__Test_Func1__Func1_Post2() = 0;
+
+	virtual void AddHook__Test_Func2__Func2_Pre1() = 0;
+	virtual void AddHook__Test_Func2__Func2_Post1() = 0;
+};
+
+class TesterRefRetNonManual : public TesterRefRet
+{
+public:
+	void AddHook__Test_Func1__Func1_Pre()
+	{
+		SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
+	}
+
+	void AddHook__Test_Func1__Func1_Post()
+	{
+		SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
+	}
+
+	void AddHook__Test_Func1__Func1_Pre2()
+	{
+		SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
+	}
+
+	void AddHook__Test_Func1__Func1_Post2()
+	{
+		SH_ADD_HOOK(Test, Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
+	}
+
+	void AddHook__Test_Func2__Func2_Pre1()
+	{
+		SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_PreRecall_OverrideRet_Normal), false);
+	}
+
+	void AddHook__Test_Func2__Func2_Post1()
+	{
+		SH_ADD_HOOK(Test, Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
+	}
+};
+
+class TesterRefRetManual : public TesterRefRet
+{
+public:
+	void AddHook__Test_Func1__Func1_Pre()
+	{
+		SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre1), false);
+	}
+
+	void AddHook__Test_Func1__Func1_Post()
+	{
+		SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post1), true);
+	}
+
+	void AddHook__Test_Func1__Func1_Pre2()
+	{
+		SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Pre2), false);
+	}
+
+	void AddHook__Test_Func1__Func1_Post2()
+	{
+		SH_ADD_MANUALHOOK(Manual_Test_Func1, pTest, SH_MEMBER(&hook, &CHook::Func1_Post2), true);
+	}
+
+	void AddHook__Test_Func2__Func2_Pre1()
+	{
+		SH_ADD_MANUALHOOK(Manual_Test_Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_PreRecall_OverrideRet_Manual), false);
+	}
+
+	void AddHook__Test_Func2__Func2_Post1()
+	{
+		SH_ADD_MANUALHOOK(Manual_Test_Func2, pTest, SH_MEMBER(&hook, &CHook::Func2_Post1), true);
+	}
+};
+
+bool TestRefRet(std::string &error)
+{
+	TesterRefRet *testerNonManual = new TesterRefRetNonManual;
+	bool resNonManual = testerNonManual->doTests(error);
+	if (!resNonManual)
+	{
+		return false;
+	}
+
+	TesterRefRet *testerManual = new TesterRefRetManual;
+	bool resManual = testerManual->doTests(error);
+	if (!resManual)
+	{
+		return false;
+	}
+	return true;
 }
diff --git a/sample_mm/Makefile b/sample_mm/Makefile
index b932876..b277c0c 100644
--- a/sample_mm/Makefile
+++ b/sample_mm/Makefile
@@ -84,8 +84,8 @@ else
 	endif
 endif
 
-# if ENGINE is orig, OB, or L4D
-ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
+# if ENGINE is original or OB
+ifneq (,$(filter original orangebox,$(ENGINE)))
 	LIB_SUFFIX = _i486.$(LIB_EXT)
 else
 	LIB_PREFIX = lib
diff --git a/stub_mm/Makefile b/stub_mm/Makefile
index 8075fb6..0020247 100644
--- a/stub_mm/Makefile
+++ b/stub_mm/Makefile
@@ -84,8 +84,8 @@ else
 	endif
 endif
 
-# if ENGINE is orig, OB, or L4D
-ifneq (,$(filter original orangebox left4dead,$(ENGINE)))
+# if ENGINE is original or OB
+ifneq (,$(filter original orangebox,$(ENGINE)))
 	LIB_SUFFIX = _i486.$(LIB_EXT)
 else
 	LIB_PREFIX = lib
diff --git a/support/buildbot/package.pl b/support/buildbot/package.pl
index 8751ff1..284c1cc 100755
--- a/support/buildbot/package.pl
+++ b/support/buildbot/package.pl
@@ -67,33 +67,25 @@ else
 my ($major,$minor) = ($version =~ /^(\d+)\.(\d+)/);
 $ftp_path .= "/$major.$minor";
 
-if ($^O eq "darwin")
+my ($ftp);
+
+$ftp = Net::FTP->new($ftp_host, Debug => 0) 
+    or die "Cannot connect to host $ftp_host: $@";
+
+$ftp->login($ftp_user, $ftp_pass)
+    or die "Cannot connect to host $ftp_host as $ftp_user: " . $ftp->message . "\n";
+
+if ($ftp_path ne '')
 {
-	# Horrible workaround for weird upload failure
-	system("ftp -Vu ftp://$ftp_user:$ftp_pass\@$ftp_host/$ftp_path/$filename $filename");
+    $ftp->cwd($ftp_path)
+        or die "Cannot change to folder $ftp_path: " . $ftp->message . "\n";
 }
-else
-{
-	my ($ftp);
 
-	$ftp = Net::FTP->new($ftp_host, Debug => 0) 
-	    or die "Cannot connect to host $ftp_host: $@";
+$ftp->binary();
+$ftp->put($filename)
+    or die "Cannot drop file $filename ($ftp_path): " . $ftp->message . "\n";
 
-	$ftp->login($ftp_user, $ftp_pass)
-	    or die "Cannot connect to host $ftp_host as $ftp_user: " . $ftp->message . "\n";
-
-	if ($ftp_path ne '')
-	{
-	    $ftp->cwd($ftp_path)
-	        or die "Cannot change to folder $ftp_path: " . $ftp->message . "\n";
-	}
-
-	$ftp->binary();
-	$ftp->put($filename)
-	    or die "Cannot drop file $filename ($ftp_path): " . $ftp->message . "\n";
-
-	$ftp->close();
-}
+$ftp->close();
 
 print "File sent to drop site as $filename -- build succeeded.\n";