Skip to content

Commit 440fec0

Browse files
author
spumer
committed
Now support the 2.1.2.5 patch.
1 parent 7e2ac80 commit 440fec0

19 files changed

Lines changed: 261 additions & 67 deletions

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ PROJECT = left4fix
1919
#Uncomment for Metamod: Source enabled extension
2020
#USEMETA = true
2121

22-
OBJECTS = sdk/smsdk_ext.cpp extension.cpp util.cpp routine.cpp codepatch/patchmanager.cpp detours/on_revived_by_defib.cpp codepatch/score_code_8.cpp\
23-
detours/on_recompute_versus_completion.cpp detours/on_get_completion_by_character.cpp detours/detour.cpp asm/asm.c
22+
OBJECTS = sdk/smsdk_ext.cpp extension.cpp util.cpp routine.cpp codepatch/patchmanager.cpp detours/on_revived_by_defib.cpp codepatch/score_code.cpp\
23+
detours/end_versus_mode_round.cpp detours/on_recompute_versus_completion.cpp detours/on_get_completion_by_character.cpp detours/detour.cpp asm/asm.c
2424
#detours/end_versus_mode_round.cpp
2525
##############################################
2626
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
Left4Fix
22
========
33

4-
Extension for SourceMod written on C++ and fix major bug on servers more than 8 players: incorrect completion score calculation.
4+
Extension for SourceMod written on C++ and fix major bug on servers more than 8 players: incorrect completion score calculation.
5+
Main thread on the forum: http://forums.alliedmods.net/showthread.php?t=219774

codepatch/patch_description.txt

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
2+
UpdateMarkersReached: E8 ? ? ? ? F3 0F 2A ? ? C1 F8 02 (EAX, EBX, EDX)
3+
AddSurvivorStats: E8 ? ? ? ? C1 F8 02 (EAX, ECX, EDX)
4+
GetVersusCompletion: 8B 55 ? A1 ? ? ? ? 8B BA E8 0D 00 00 89 ? ? C1 FF 02 (EAX, EDI, EDX)
5+
6+
7+
UpdateMarkersReached_patch:
8+
9+
E9 ? ? ? ? /* JMP [address] */
10+
8B 80 E8 0D 00 00 /* mov eax, [eax+3560] */
11+
31 D2 /* xor edx, edx */
12+
BB 0A 00 00 00 /* mov ebx, 10 */
13+
F7 F3 /* div ebx */
14+
E9 ? ? ? ? /* JMP [address] ;jump to next instruction */
15+
/* NOP 3 bytes (sar eax, 2) */
16+
17+
Result:
18+
{ 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xBB, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF3 }
19+
20+
AddSurvivorStats_patch:
21+
E9 ? ? ? ? /* JMP [address] */
22+
8B 80 E8 0D 00 00 /* mov eax, [eax+3560] */
23+
31 D2 /* xor edx, edx */
24+
B9 0A 00 00 00 /* mov ecx, 10 */
25+
F7 F1 /* div ecx */
26+
E9 ? ? ? ? /* JMP [address] ;jump to next instruction */
27+
Result:
28+
{ 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xB9, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF1 }
29+
30+
GetVersusCompletion_patch:
31+
32+
E9 ? ? ? ? /* JMP [address] */
33+
8B 45 08 /* mov eax, [ebp+arg_0] */
34+
/* copy A1 ? ? ? ? to trampoline end */
35+
8B 80 E8 0D 00 00 /* mov eax, [eax+3560] */
36+
/* copy 89 ? ? to trampoline end */
37+
31 D2 /* xor edx, edx */
38+
BF 0A 00 00 00 /* mov edi, 10 */
39+
F7 F7 /* div edi */
40+
89 C7 /* mov edi, eax */
41+
E9 ? ? ? ? /* JMP [address] ;jump to next instruction */
42+
Result:
43+
{ 0x8B, 0x45, 0x08, 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xBF, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF7, 0x89, 0xC7 }
44+

codepatch/score_code.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,24 @@
3434
#include "asm/asm.h"
3535
#include "CDetour/detourhelpers.h"
3636

37-
// TODO: Replace sig search to offsets, copy original by copy_bytes and restore when unpatch.
37+
#define OP_CALL 0xE8
38+
#define OP_CALL_SIZE 5
3839

39-
unsigned char UpdateMarkersReached_orig[] = { 0xE8, 0x35, 0x69, 0xBA, 0xFF, 0xC1, 0xF8, 0x02 };
40-
unsigned char UpdateMarkersReached_patch[] = { 0x8B, 0x80, 0x90, 0x04, 0x00, 0x00, 0x31, 0xD2, 0xB9, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF1 };
40+
#define OP_MOV 0xA1
41+
#define OP_MOV_SIZE 5
4142

42-
unsigned char AddSurvivorStats_orig[] = { 0xE8, 0xF1, 0x9C, 0xB7, 0xFF, 0xC1, 0xF8, 0x02 };
43-
unsigned char AddSurvivorStats_patch[] = { 0x8B, 0x80, 0x90, 0x04, 0x00, 0x00, 0x31, 0xD2, 0xB9, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF1 };
43+
// TODO: Create CUT/PASTE masks functions for wrap instructions inside my patch
4444

45-
unsigned char GetVersusCompletion_orig[] = { 0x8B, 0xB8, 0x90, 0x04, 0x00, 0x00, 0xC1, 0xFF, 0x02 };
46-
unsigned char GetVersusCompletion_patch[] = { 0x8B, 0x80, 0x90, 0x04, 0x00, 0x00, 0x31, 0xD2, 0xBF, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF7, 0x89, 0xC7 };
45+
unsigned char UpdateMarkersReached_orig[] = { 0xE8, 0x2A, 0x2A, 0x2A, 0x2A, 0xF3, 0x0F, 0x2A, 0x2A, 0x2A, 0xC1, 0xF8, 0x02 };
46+
unsigned char UpdateMarkersReached_patch[] = { 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xBB, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF3 };
4747

48-
#ifdef _DEBUG
48+
unsigned char AddSurvivorStats_orig[] = { 0xE8, 0x2A, 0x2A, 0x2A, 0x2A, 0xC1, 0xF8, 0x02 };
49+
unsigned char AddSurvivorStats_patch[] = { 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xB9, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF1 };
50+
51+
unsigned char GetVersusCompletion_orig[] = { 0x8B, 0x55, 0x2A, 0xA1, 0x2A, 0x2A, 0x2A, 0x2A, 0x8B, 0xBA, 0xE8, 0x0D, 0x00, 0x00, 0x89, 0x2A, 0x2A, 0xC1, 0xFF, 0x02 };
52+
unsigned char GetVersusCompletion_patch[] = { 0x8B, 0x45, 0x08, 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xBF, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF7, 0x89, 0xC7 };
53+
54+
#ifdef DEBUG
4955
void memDump(unsigned char *pAddr, size_t len) {
5056
g_pSmmAPI->ConPrintf("Start dump at: %p\n", pAddr);
5157
size_t llen = len;
@@ -69,24 +75,39 @@ void ScoreCode::Patch() {
6975

7076
ISourcePawnEngine *sengine = g_pSM->GetScriptingEngine();
7177

78+
// prepare the trampoline
7279
m_injectMarker = (unsigned char *)sengine->AllocatePageMemory(sizeof(UpdateMarkersReached_patch) + OP_JMP_SIZE);
7380
copy_bytes(UpdateMarkersReached_patch, m_injectMarker, sizeof(UpdateMarkersReached_patch));
74-
inject_jmp(m_injectMarker + sizeof(UpdateMarkersReached_patch), m_pMarkers + sizeof(UpdateMarkersReached_orig));
81+
inject_jmp(m_injectMarker + sizeof(UpdateMarkersReached_patch), m_pMarkers + OP_CALL_SIZE);
82+
// copy original code to our buffer
7583
SetMemPatchable(m_pMarkers, sizeof(UpdateMarkersReached_orig));
84+
copy_bytes(m_pMarkers, UpdateMarkersReached_orig, sizeof(UpdateMarkersReached_orig));
85+
// inject jmp to trampoline and nop some bytes after target instruction
7686
inject_jmp(m_pMarkers, m_injectMarker);
77-
fill_nop(m_pMarkers + OP_JMP_SIZE, sizeof(UpdateMarkersReached_orig) - OP_JMP_SIZE);
87+
fill_nop(m_pMarkers + sizeof(UpdateMarkersReached_orig) - 3, 3);
7888

89+
// prepare the trampoline
7990
m_injectStats = (unsigned char *)sengine->AllocatePageMemory(sizeof(AddSurvivorStats_patch) + OP_JMP_SIZE);
8091
copy_bytes(AddSurvivorStats_patch, m_injectStats, sizeof(AddSurvivorStats_patch));
8192
inject_jmp(m_injectStats + sizeof(AddSurvivorStats_patch), m_pL4DStats + sizeof(AddSurvivorStats_orig));
93+
// copy original code to our buffer
8294
SetMemPatchable(m_pL4DStats, sizeof(AddSurvivorStats_orig));
95+
copy_bytes(m_pL4DStats, AddSurvivorStats_orig, sizeof(AddSurvivorStats_orig));
96+
// inject jmp to trampoline
8397
inject_jmp(m_pL4DStats, m_injectStats);
8498
fill_nop(m_pL4DStats + OP_JMP_SIZE, sizeof(AddSurvivorStats_orig) - OP_JMP_SIZE);
8599

100+
// prepare the trampoline
86101
m_injectCompl = (unsigned char *)sengine->AllocatePageMemory(sizeof(GetVersusCompletion_patch) + OP_JMP_SIZE);
87-
copy_bytes(GetVersusCompletion_patch, m_injectCompl, sizeof(GetVersusCompletion_patch));
88-
inject_jmp(m_injectCompl + sizeof(GetVersusCompletion_patch), m_pCompletion + sizeof(GetVersusCompletion_orig));
102+
unsigned char *pInjectEnd = m_injectCompl;
103+
copy_bytes(GetVersusCompletion_patch, m_injectCompl, sizeof(GetVersusCompletion_patch)); pInjectEnd += sizeof(GetVersusCompletion_patch);
104+
copy_bytes(m_pCompletion + 3, pInjectEnd, OP_MOV_SIZE); pInjectEnd += OP_MOV_SIZE;
105+
copy_bytes(m_pCompletion + sizeof(GetVersusCompletion_orig) - 6, pInjectEnd, 3); pInjectEnd += 3;
106+
inject_jmp(pInjectEnd, m_pCompletion + sizeof(GetVersusCompletion_orig));
107+
// copy original code to our buffer
89108
SetMemPatchable(m_pCompletion, sizeof(GetVersusCompletion_orig));
109+
copy_bytes(m_pCompletion, GetVersusCompletion_orig, sizeof(GetVersusCompletion_orig));
110+
// inject jmp to trampoline
90111
inject_jmp(m_pCompletion, m_injectCompl);
91112
fill_nop(m_pCompletion + OP_JMP_SIZE, sizeof(GetVersusCompletion_orig) - OP_JMP_SIZE);
92113

detours/end_versus_mode_round.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/**
2+
* vim: set ts=4 :
3+
* =============================================================================
4+
* Left 4 Fix SourceMod Extension
5+
* Copyright (C) 2013 Spumer.
6+
* =============================================================================
7+
*
8+
* This program is free software; you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License, version 3.0, as published by the
10+
* Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15+
* details.
16+
*
17+
* You should have received a copy of the GNU General Public License along with
18+
* this program. If not, see <http://www.gnu.org/licenses/>.
19+
*
20+
* As a special exception, AlliedModders LLC gives you permission to link the
21+
* code of this program (as well as its derivative works) to "Half-Life 2," the
22+
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23+
* by the Valve Corporation. You must obey the GNU General Public License in
24+
* all respects for all other code used. Additionally, AlliedModders LLC grants
25+
* this exception to all derivative works. AlliedModders LLC defines further
26+
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27+
* or <http://www.sourcemod.net/license.php>.
28+
*
29+
* Version: $Id$
30+
*/
31+
32+
#include "end_versus_mode_round.h"
33+
#include "extension.h"
34+
35+
namespace Detours
36+
{
37+
void l4fx_EndVersusModeRound::OnEndVersusModeRound(bool countSurvivors)
38+
{
39+
if(g_bRoundEnd_Pre) return;
40+
g_bRoundEnd_Pre = true;
41+
(this->*(GetTrampoline()))(countSurvivors);
42+
43+
memset(g_iHighestVersusSurvivorCompletion, 0, sizeof(g_iHighestVersusSurvivorCompletion));
44+
memset(g_players, 0, sizeof(g_players));
45+
memset(g_scores, 0, sizeof(g_scores));
46+
__sync_and_and_fetch(&g_totalResult, 0); // g_totalResult = 0;
47+
return;
48+
}
49+
};

detours/end_versus_mode_round.h

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* vim: set ts=4 :
3+
* =============================================================================
4+
* Left 4 Fix SourceMod Extension
5+
* Copyright (C) 2013 Spumer.
6+
* =============================================================================
7+
*
8+
* This program is free software; you can redistribute it and/or modify it under
9+
* the terms of the GNU General Public License, version 3.0, as published by the
10+
* Free Software Foundation.
11+
*
12+
* This program is distributed in the hope that it will be useful, but WITHOUT
13+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14+
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
15+
* details.
16+
*
17+
* You should have received a copy of the GNU General Public License along with
18+
* this program. If not, see <http://www.gnu.org/licenses/>.
19+
*
20+
* As a special exception, AlliedModders LLC gives you permission to link the
21+
* code of this program (as well as its derivative works) to "Half-Life 2," the
22+
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23+
* by the Valve Corporation. You must obey the GNU General Public License in
24+
* all respects for all other code used. Additionally, AlliedModders LLC grants
25+
* this exception to all derivative works. AlliedModders LLC defines further
26+
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27+
* or <http://www.sourcemod.net/license.php>.
28+
*
29+
* Version: $Id$
30+
*/
31+
32+
#ifndef _INCLUDE_SOURCEMOD_DETOUR_END_VERSUS_MODE_ROUND_H_
33+
#define _INCLUDE_SOURCEMOD_DETOUR_END_VERSUS_MODE_ROUND_H_
34+
35+
#include "detour_template.h"
36+
37+
namespace Detours {
38+
39+
class l4fx_EndVersusModeRound;
40+
typedef void (l4fx_EndVersusModeRound::*EndVersusModeRoundFunc)(bool);
41+
42+
class l4fx_EndVersusModeRound : public DetourTemplate<EndVersusModeRoundFunc, l4fx_EndVersusModeRound>
43+
{
44+
private: //note: implementation of DetourTemplate abstracts
45+
46+
void OnEndVersusModeRound(bool countSurvivors);
47+
48+
// get the signature name from the game conf
49+
virtual const char *GetSignatureName()
50+
{
51+
return "EndVersusModeRound";
52+
}
53+
54+
//notify our patch system which function should be used as the detour
55+
virtual EndVersusModeRoundFunc GetDetour()
56+
{
57+
return &l4fx_EndVersusModeRound::OnEndVersusModeRound;
58+
}
59+
};
60+
61+
};
62+
#endif

detours/on_recompute_versus_completion.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ namespace Detours
9999
if(pPlayer == NULL) continue;
100100

101101
// if(GET_TEAM(client) == 2) {
102-
if( *reinterpret_cast<uint8_t*>((unsigned char*)pPlayer + 576) == 2 ) { // Get player team index
102+
if( *reinterpret_cast<uint8_t*>((unsigned char*)pPlayer + 588) == 2 ) { // Get player team index
103103
if(IsDead(pPlayer)) continue;
104104
*pCompl = g_scores[client] = GetVersusCompletionFunc(pGameRules, pPlayer);
105105
result += *pCompl++;

detours/on_recompute_versus_completion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ class RecomputeVersusCompletion: public DetourTemplate<OnRecomputeFunc, Recomput
6060

6161
static int getHighest(const void* p1, const void* p2) { return *(int*)p2 - *(int*)p1; }
6262

63-
static bool IsDead(CBaseEntity *pPlayer) { return *(bool*)((unsigned char*)pPlayer+252); }
63+
static bool IsDead(CBaseEntity *pPlayer) { return *(bool*)((unsigned char*)pPlayer+260); }
6464
};
6565

6666
};

detours/on_revived_by_defib.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/**
22
* vim: set ts=4 :
33
* =============================================================================
4-
* Left 4 Downtown SourceMod Extension
5-
* Copyright (C) 2009 Igor "Downtown1" Smirnov.
4+
* Left 4 Fix SourceMod Extension
5+
* Copyright (C) 2013 Spumer.
66
* =============================================================================
77
*
88
* This program is free software; you can redistribute it and/or modify it under

detours/on_revived_by_defib.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
/**
22
* vim: set ts=4 :
33
* =============================================================================
4-
* Left 4 Downtown SourceMod Extension
5-
* Copyright (C) 2009 Igor "Downtown1" Smirnov.
4+
* Left 4 Fix SourceMod Extension
5+
* Copyright (C) 2013 Spumer.
66
* =============================================================================
77
*
88
* This program is free software; you can redistribute it and/or modify it under

0 commit comments

Comments
 (0)