Skip to content

Commit

Permalink
Now support the 2.1.2.5 patch.
Browse files Browse the repository at this point in the history
  • Loading branch information
spumer committed Jul 8, 2013
1 parent 7e2ac80 commit 440fec0
Show file tree
Hide file tree
Showing 19 changed files with 261 additions and 67 deletions.
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ PROJECT = left4fix
#Uncomment for Metamod: Source enabled extension
#USEMETA = true

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\
detours/on_recompute_versus_completion.cpp detours/on_get_completion_by_character.cpp detours/detour.cpp asm/asm.c
OBJECTS = sdk/smsdk_ext.cpp extension.cpp util.cpp routine.cpp codepatch/patchmanager.cpp detours/on_revived_by_defib.cpp codepatch/score_code.cpp\
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
#detours/end_versus_mode_round.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Left4Fix
========

Extension for SourceMod written on C++ and fix major bug on servers more than 8 players: incorrect completion score calculation.
Extension for SourceMod written on C++ and fix major bug on servers more than 8 players: incorrect completion score calculation.
Main thread on the forum: http://forums.alliedmods.net/showthread.php?t=219774
44 changes: 44 additions & 0 deletions codepatch/patch_description.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@

UpdateMarkersReached: E8 ? ? ? ? F3 0F 2A ? ? C1 F8 02 (EAX, EBX, EDX)
AddSurvivorStats: E8 ? ? ? ? C1 F8 02 (EAX, ECX, EDX)
GetVersusCompletion: 8B 55 ? A1 ? ? ? ? 8B BA E8 0D 00 00 89 ? ? C1 FF 02 (EAX, EDI, EDX)


UpdateMarkersReached_patch:

E9 ? ? ? ? /* JMP [address] */
8B 80 E8 0D 00 00 /* mov eax, [eax+3560] */
31 D2 /* xor edx, edx */
BB 0A 00 00 00 /* mov ebx, 10 */
F7 F3 /* div ebx */
E9 ? ? ? ? /* JMP [address] ;jump to next instruction */
/* NOP 3 bytes (sar eax, 2) */

Result:
{ 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xBB, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF3 }

AddSurvivorStats_patch:
E9 ? ? ? ? /* JMP [address] */
8B 80 E8 0D 00 00 /* mov eax, [eax+3560] */
31 D2 /* xor edx, edx */
B9 0A 00 00 00 /* mov ecx, 10 */
F7 F1 /* div ecx */
E9 ? ? ? ? /* JMP [address] ;jump to next instruction */
Result:
{ 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xB9, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF1 }

GetVersusCompletion_patch:

E9 ? ? ? ? /* JMP [address] */
8B 45 08 /* mov eax, [ebp+arg_0] */
/* copy A1 ? ? ? ? to trampoline end */
8B 80 E8 0D 00 00 /* mov eax, [eax+3560] */
/* copy 89 ? ? to trampoline end */
31 D2 /* xor edx, edx */
BF 0A 00 00 00 /* mov edi, 10 */
F7 F7 /* div edi */
89 C7 /* mov edi, eax */
E9 ? ? ? ? /* JMP [address] ;jump to next instruction */
Result:
{ 0x8B, 0x45, 0x08, 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xBF, 0x0A, 0x00, 0x00, 0x00, 0xF7, 0xF7, 0x89, 0xC7 }

45 changes: 33 additions & 12 deletions codepatch/score_code.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,24 @@
#include "asm/asm.h"
#include "CDetour/detourhelpers.h"

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

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

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

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

#ifdef _DEBUG
unsigned char AddSurvivorStats_orig[] = { 0xE8, 0x2A, 0x2A, 0x2A, 0x2A, 0xC1, 0xF8, 0x02 };
unsigned char AddSurvivorStats_patch[] = { 0x8B, 0x80, 0xE8, 0x0D, 0x00, 0x00, 0x31, 0xD2, 0xB9, TEAM_SIZE, 0x00, 0x00, 0x00, 0xF7, 0xF1 };

unsigned char GetVersusCompletion_orig[] = { 0x8B, 0x55, 0x2A, 0xA1, 0x2A, 0x2A, 0x2A, 0x2A, 0x8B, 0xBA, 0xE8, 0x0D, 0x00, 0x00, 0x89, 0x2A, 0x2A, 0xC1, 0xFF, 0x02 };
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 };

#ifdef DEBUG
void memDump(unsigned char *pAddr, size_t len) {
g_pSmmAPI->ConPrintf("Start dump at: %p\n", pAddr);
size_t llen = len;
Expand All @@ -69,24 +75,39 @@ void ScoreCode::Patch() {

ISourcePawnEngine *sengine = g_pSM->GetScriptingEngine();

// prepare the trampoline
m_injectMarker = (unsigned char *)sengine->AllocatePageMemory(sizeof(UpdateMarkersReached_patch) + OP_JMP_SIZE);
copy_bytes(UpdateMarkersReached_patch, m_injectMarker, sizeof(UpdateMarkersReached_patch));
inject_jmp(m_injectMarker + sizeof(UpdateMarkersReached_patch), m_pMarkers + sizeof(UpdateMarkersReached_orig));
inject_jmp(m_injectMarker + sizeof(UpdateMarkersReached_patch), m_pMarkers + OP_CALL_SIZE);
// copy original code to our buffer
SetMemPatchable(m_pMarkers, sizeof(UpdateMarkersReached_orig));
copy_bytes(m_pMarkers, UpdateMarkersReached_orig, sizeof(UpdateMarkersReached_orig));
// inject jmp to trampoline and nop some bytes after target instruction
inject_jmp(m_pMarkers, m_injectMarker);
fill_nop(m_pMarkers + OP_JMP_SIZE, sizeof(UpdateMarkersReached_orig) - OP_JMP_SIZE);
fill_nop(m_pMarkers + sizeof(UpdateMarkersReached_orig) - 3, 3);

// prepare the trampoline
m_injectStats = (unsigned char *)sengine->AllocatePageMemory(sizeof(AddSurvivorStats_patch) + OP_JMP_SIZE);
copy_bytes(AddSurvivorStats_patch, m_injectStats, sizeof(AddSurvivorStats_patch));
inject_jmp(m_injectStats + sizeof(AddSurvivorStats_patch), m_pL4DStats + sizeof(AddSurvivorStats_orig));
// copy original code to our buffer
SetMemPatchable(m_pL4DStats, sizeof(AddSurvivorStats_orig));
copy_bytes(m_pL4DStats, AddSurvivorStats_orig, sizeof(AddSurvivorStats_orig));
// inject jmp to trampoline
inject_jmp(m_pL4DStats, m_injectStats);
fill_nop(m_pL4DStats + OP_JMP_SIZE, sizeof(AddSurvivorStats_orig) - OP_JMP_SIZE);

// prepare the trampoline
m_injectCompl = (unsigned char *)sengine->AllocatePageMemory(sizeof(GetVersusCompletion_patch) + OP_JMP_SIZE);
copy_bytes(GetVersusCompletion_patch, m_injectCompl, sizeof(GetVersusCompletion_patch));
inject_jmp(m_injectCompl + sizeof(GetVersusCompletion_patch), m_pCompletion + sizeof(GetVersusCompletion_orig));
unsigned char *pInjectEnd = m_injectCompl;
copy_bytes(GetVersusCompletion_patch, m_injectCompl, sizeof(GetVersusCompletion_patch)); pInjectEnd += sizeof(GetVersusCompletion_patch);
copy_bytes(m_pCompletion + 3, pInjectEnd, OP_MOV_SIZE); pInjectEnd += OP_MOV_SIZE;
copy_bytes(m_pCompletion + sizeof(GetVersusCompletion_orig) - 6, pInjectEnd, 3); pInjectEnd += 3;
inject_jmp(pInjectEnd, m_pCompletion + sizeof(GetVersusCompletion_orig));
// copy original code to our buffer
SetMemPatchable(m_pCompletion, sizeof(GetVersusCompletion_orig));
copy_bytes(m_pCompletion, GetVersusCompletion_orig, sizeof(GetVersusCompletion_orig));
// inject jmp to trampoline
inject_jmp(m_pCompletion, m_injectCompl);
fill_nop(m_pCompletion + OP_JMP_SIZE, sizeof(GetVersusCompletion_orig) - OP_JMP_SIZE);

Expand Down
49 changes: 49 additions & 0 deletions detours/end_versus_mode_round.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* vim: set ts=4 :
* =============================================================================
* Left 4 Fix SourceMod Extension
* Copyright (C) 2013 Spumer.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/

#include "end_versus_mode_round.h"
#include "extension.h"

namespace Detours
{
void l4fx_EndVersusModeRound::OnEndVersusModeRound(bool countSurvivors)
{
if(g_bRoundEnd_Pre) return;
g_bRoundEnd_Pre = true;
(this->*(GetTrampoline()))(countSurvivors);

memset(g_iHighestVersusSurvivorCompletion, 0, sizeof(g_iHighestVersusSurvivorCompletion));
memset(g_players, 0, sizeof(g_players));
memset(g_scores, 0, sizeof(g_scores));
__sync_and_and_fetch(&g_totalResult, 0); // g_totalResult = 0;
return;
}
};
62 changes: 62 additions & 0 deletions detours/end_versus_mode_round.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* vim: set ts=4 :
* =============================================================================
* Left 4 Fix SourceMod Extension
* Copyright (C) 2013 Spumer.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, version 3.0, as published by the
* Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, AlliedModders LLC gives you permission to link the
* code of this program (as well as its derivative works) to "Half-Life 2," the
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
* by the Valve Corporation. You must obey the GNU General Public License in
* all respects for all other code used. Additionally, AlliedModders LLC grants
* this exception to all derivative works. AlliedModders LLC defines further
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
* or <http://www.sourcemod.net/license.php>.
*
* Version: $Id$
*/

#ifndef _INCLUDE_SOURCEMOD_DETOUR_END_VERSUS_MODE_ROUND_H_
#define _INCLUDE_SOURCEMOD_DETOUR_END_VERSUS_MODE_ROUND_H_

#include "detour_template.h"

namespace Detours {

class l4fx_EndVersusModeRound;
typedef void (l4fx_EndVersusModeRound::*EndVersusModeRoundFunc)(bool);

class l4fx_EndVersusModeRound : public DetourTemplate<EndVersusModeRoundFunc, l4fx_EndVersusModeRound>
{
private: //note: implementation of DetourTemplate abstracts

void OnEndVersusModeRound(bool countSurvivors);

// get the signature name from the game conf
virtual const char *GetSignatureName()
{
return "EndVersusModeRound";
}

//notify our patch system which function should be used as the detour
virtual EndVersusModeRoundFunc GetDetour()
{
return &l4fx_EndVersusModeRound::OnEndVersusModeRound;
}
};

};
#endif
2 changes: 1 addition & 1 deletion detours/on_recompute_versus_completion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ namespace Detours
if(pPlayer == NULL) continue;

// if(GET_TEAM(client) == 2) {
if( *reinterpret_cast<uint8_t*>((unsigned char*)pPlayer + 576) == 2 ) { // Get player team index
if( *reinterpret_cast<uint8_t*>((unsigned char*)pPlayer + 588) == 2 ) { // Get player team index
if(IsDead(pPlayer)) continue;
*pCompl = g_scores[client] = GetVersusCompletionFunc(pGameRules, pPlayer);
result += *pCompl++;
Expand Down
2 changes: 1 addition & 1 deletion detours/on_recompute_versus_completion.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class RecomputeVersusCompletion: public DetourTemplate<OnRecomputeFunc, Recomput

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

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

};
Expand Down
4 changes: 2 additions & 2 deletions detours/on_revived_by_defib.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 :
* =============================================================================
* Left 4 Downtown SourceMod Extension
* Copyright (C) 2009 Igor "Downtown1" Smirnov.
* Left 4 Fix SourceMod Extension
* Copyright (C) 2013 Spumer.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
Expand Down
4 changes: 2 additions & 2 deletions detours/on_revived_by_defib.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/**
* vim: set ts=4 :
* =============================================================================
* Left 4 Downtown SourceMod Extension
* Copyright (C) 2009 Igor "Downtown1" Smirnov.
* Left 4 Fix SourceMod Extension
* Copyright (C) 2013 Spumer.
* =============================================================================
*
* This program is free software; you can redistribute it and/or modify it under
Expand Down
2 changes: 1 addition & 1 deletion event_player_death.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class PlayerDeath : public IGameEventListener2
if(client) {
CBaseEntity *pPlayer = UTIL_GetCBaseEntity(client, true);
if(pPlayer == NULL) return;
if( *reinterpret_cast<uint8_t*>((unsigned char*)pPlayer + 576) == 2 ) { // Get player team index
if( *reinterpret_cast<uint8_t*>((unsigned char*)pPlayer + 588) == 2 ) { // Get player team index
r_nowDead( GetAbsOrigin(pPlayer), g_scores[client], g_players );
}
}
Expand Down
6 changes: 1 addition & 5 deletions event_round_start.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ class RoundStart : public IGameEventListener2
int GetEventDebugID(void) { return EVENT_DEBUG_ID_INIT; }
void FireGameEvent(IGameEvent* pEvent)
{
// Detours::g_bRoundEnd_Pre = false;
memset(g_iHighestVersusSurvivorCompletion, 0, sizeof(g_iHighestVersusSurvivorCompletion));
memset(g_players, 0, sizeof(g_players));
memset(g_scores, 0, sizeof(g_scores));
g_totalResult = 0;
Detours::g_bRoundEnd_Pre = false;
}
};

Expand Down
Loading

0 comments on commit 440fec0

Please sign in to comment.