From f3c99ade10b8176c49f42da655b0d813a5b863ce Mon Sep 17 00:00:00 2001 From: Forgetest <33988868+jensewe@users.noreply.github.com> Date: Sun, 3 May 2026 17:47:56 +0800 Subject: [PATCH 1/2] Update l4d2_fix_changelevel --- .../gamedata/l4d2_fix_changelevel.txt | 42 +++++++++++++- .../scripting/l4d2_fix_changelevel.sp | 56 +++++++++++++++---- 2 files changed, 86 insertions(+), 12 deletions(-) diff --git a/addons/sourcemod/gamedata/l4d2_fix_changelevel.txt b/addons/sourcemod/gamedata/l4d2_fix_changelevel.txt index 6c6c1b612..521a59ab6 100644 --- a/addons/sourcemod/gamedata/l4d2_fix_changelevel.txt +++ b/addons/sourcemod/gamedata/l4d2_fix_changelevel.txt @@ -37,13 +37,19 @@ "linux" "944" "windows" "944" } + + "CDirector::m_szOriginalMap" + { + "linux" "948" + "windows" "948" + } } "Addresses" { "CDirector::m_isTransitioning" { - "signature" "CDirector::OnBeginTransition" + "signature" "CDirector::OnBeginTransition" "linux" { "read" "14" @@ -53,6 +59,32 @@ "read" "26" } } + + "s_landmarkName" + { + "signature" "InfoChangelevel::StartChangeLevel" + "linux" + { + "read" "88" + } + "windows" + { + "read" "77" + } + } + + "s_landmarkPosition" + { + "signature" "InfoChangelevel::StartChangeLevel" + "linux" + { + "read" "190" + } + "windows" + { + "read" "160" + } + } } "Signatures" @@ -90,6 +122,14 @@ "windows" "\x55\x8B\x2A\x2A\x2A\x2A\x2A\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x2A\x2A\x89\x2A\x2A\xA1\x2A\x2A\x2A\x2A\x56\x8B\x2A\x2A\x57\x8B" /* 55 8B ? ? ? ? ? ? ? A1 ? ? ? ? ? ? 89 ? ? A1 ? ? ? ? 56 8B ? ? 57 8B */ } + + "InfoChangelevel::StartChangeLevel" + { + "library" "server" + "linux" "@_ZN15InfoChangelevel16StartChangeLevelEPK10Checkpoint" + "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x83\x78\x30\x00\x56\x8B\xF1\x74" + // 55 8B EC A1 ? ? ? ? 83 78 30 00 56 8B F1 74 + } } } } \ No newline at end of file diff --git a/addons/sourcemod/scripting/l4d2_fix_changelevel.sp b/addons/sourcemod/scripting/l4d2_fix_changelevel.sp index f19de3f3e..01a2b852a 100644 --- a/addons/sourcemod/scripting/l4d2_fix_changelevel.sp +++ b/addons/sourcemod/scripting/l4d2_fix_changelevel.sp @@ -6,7 +6,7 @@ #include #include -#define PLUGIN_VERSION "1.1" +#define PLUGIN_VERSION "1.2" public Plugin myinfo = { @@ -81,7 +81,10 @@ Handle g_CallOnBeginTransition; Handle g_CallOnBeginChangeLevel; int g_iOffs_m_mapDurationTimer; int g_iOffs_m_flTotalMissionElaspedTime; +int g_iOffs_m_szOriginalMap; Address gp_m_isTransitioning; +Address gp_s_landmarkName; +Address gp_s_landmarkPosition; methodmap CDirector { public void ClearTeamScores(bool newCampaign) { @@ -96,9 +99,15 @@ methodmap CDirector { property float m_flTotalMissionElaspedTime { public set(float flTotalMissionElaspedTime) { StoreToAddress(view_as
(this) + view_as
(g_iOffs_m_flTotalMissionElaspedTime), flTotalMissionElaspedTime, NumberType_Int32); } } + property Address m_szOriginalMap { + public get() { return view_as
(this) + view_as
(g_iOffs_m_szOriginalMap); } + } public bool IsTransitioning() { return LoadFromAddress(gp_m_isTransitioning, NumberType_Int8); } + public void SetOriginalMap(const char[] map) { + UTIL_StoreToAddressString(this.m_szOriginalMap, map, 32); + } } CDirector TheDirector; @@ -110,20 +119,23 @@ public void OnPluginStart() {SDKType_Bool, SDKPass_Plain} }; g_CallClearTeamScores = gd.CreateSDKCallOrFail(SDKCall_Raw, SDKConf_Signature, "CDirector::ClearTeamScores", params, sizeof(params), false); - + SDKCallParamsWrapper params2[] = { {SDKType_Bool, SDKPass_Plain} }; g_CallOnBeginTransition = gd.CreateSDKCallOrFail(SDKCall_Raw, SDKConf_Signature, "CDirector::OnBeginTransition", params2, sizeof(params2), false); - + SDKCallParamsWrapper params3[] = { {SDKType_String, SDKPass_Pointer} }; g_CallOnBeginChangeLevel = gd.CreateSDKCallOrFail(SDKCall_GameRules, SDKConf_Signature, "CTerrorGameRules::OnBeginChangeLevel", params3, sizeof(params3), false); - + g_iOffs_m_mapDurationTimer = gd.GetOffsetOrFail("CDirector::m_mapDurationTimer"); g_iOffs_m_flTotalMissionElaspedTime = gd.GetOffsetOrFail("CDirector::m_flTotalMissionElaspedTime"); + g_iOffs_m_szOriginalMap = gd.GetOffsetOrFail("CDirector::m_szOriginalMap"); gp_m_isTransitioning = gd.GetAddressOrFail("CDirector::m_isTransitioning"); + gp_s_landmarkName = gd.GetAddressOrFail("s_landmarkName"); + gp_s_landmarkPosition = gd.GetAddressOrFail("s_landmarkPosition"); delete gd.CreateDetourOrFail("CVEngineServer::ChangeLevel", DTR__CVEngineServer__ChangeLevel); delete gd; @@ -132,29 +144,32 @@ public void OnPluginStart() public void OnAllPluginsLoaded() { TheDirector = view_as(L4D_GetPointer(POINTER_DIRECTOR)); + if (!TheDirector) + { + LogError("Failed to retrieve TheDirector pointer from left4dhooks"); + } } MRESReturn DTR__CVEngineServer__ChangeLevel(DHookParam hParams) { if (!TheDirector) - { - LogError("Failed to retrieve TheDirector pointer from left4dhooks"); return MRES_Ignored; - } - + char map[64]/*, reason[64]*/; hParams.GetString(1, map, sizeof(map)); // if (!hParams.IsNull(2)) // hParams.GetString(2, reason, sizeof(reason)); - + if (TheDirector.IsTransitioning()) return MRES_Ignored; - + TheDirector.ClearTeamScores(true); - + ITimer_Start(TheDirector.m_mapDurationTimer); TheDirector.m_flTotalMissionElaspedTime = 0.0; + TheDirector.SetOriginalMap(map); + ClearTransitionedLandmarkName(); TheDirector.OnBeginTransition(false); GameRules__OnBeginChangeLevel(map); @@ -164,4 +179,23 @@ MRESReturn DTR__CVEngineServer__ChangeLevel(DHookParam hParams) void GameRules__OnBeginChangeLevel(const char[] map) { SDKCall(g_CallOnBeginChangeLevel, map); +} + +void ClearTransitionedLandmarkName() +{ + StoreToAddress(gp_s_landmarkName, 0, NumberType_Int8); + StoreToAddress(gp_s_landmarkPosition, 0.0, NumberType_Int32); + StoreToAddress(gp_s_landmarkPosition + view_as
(4), 0.0, NumberType_Int32); + StoreToAddress(gp_s_landmarkPosition + view_as
(8), 0.0, NumberType_Int32); +} + +void UTIL_StoreToAddressString(Address dest, const char[] src, int maxlength) +{ + int len = strlen(src); + if (len > maxlength - 1) + len = maxlength - 1; + for (int i = 0; i < len; ++i) { + StoreToAddress(dest + view_as
(i), src[i], NumberType_Int8); + } + StoreToAddress(dest + view_as
(len), 0, NumberType_Int8); } \ No newline at end of file From 065a301bdacbca37815b7d931c7ad1af9102cf43 Mon Sep 17 00:00:00 2001 From: Forgetest <33988868+jensewe@users.noreply.github.com> Date: Sun, 3 May 2026 17:48:25 +0800 Subject: [PATCH 2/2] Add compiled l4d2_fix_changelevel --- .../plugins/fixes/l4d2_fix_changelevel.smx | Bin 7307 -> 7911 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/addons/sourcemod/plugins/fixes/l4d2_fix_changelevel.smx b/addons/sourcemod/plugins/fixes/l4d2_fix_changelevel.smx index 27a822a5b344b5cf5bb3356a5945dacca3bedcdd..06576165b5f9e2582d6a4be8f91ca7af59e9bd67 100644 GIT binary patch delta 7730 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 bvSQpwu>sdQRn@NQlS;=LUh`~cdY=Cu8gvF0 delta 7121 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 CfvNid