Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
name: Build
runs-on: ${{ matrix.os }}
env:
HL2SDKCS2: ${{ github.workspace }}/CS2Fixes-RampbugFix/sdk
HL2SDKCS2: ${{ github.workspace }}/CS2-SurfFixes/sdk
container: ${{ matrix.container }}
strategy:
fail-fast: false
Expand All @@ -40,7 +40,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
with:
path: CS2Fixes-RampbugFix
path: CS2-SurfFixes
submodules: recursive
fetch-depth: 0

Expand All @@ -63,7 +63,7 @@ jobs:
cd ambuild && python setup.py install && cd ..

- name: Build
working-directory: CS2Fixes-RampbugFix
working-directory: CS2-SurfFixes
shell: bash
run: |
mkdir build && cd build
Expand All @@ -74,7 +74,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: ${{ runner.os }}
path: CS2Fixes-RampbugFix/build/package
path: CS2-SurfFixes/build/package

release:
name: Release
Expand Down
4 changes: 2 additions & 2 deletions AMBuilder
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
import os
import subprocess

MMSPlugin.plugin_name = 'cs2fixes-rampbugfix'
MMSPlugin.plugin_alias = 'cs2fixes-rampbugfix'
MMSPlugin.plugin_name = 'CS2-SurfFixes'
MMSPlugin.plugin_alias = 'CS2-SurfFixes'

for sdk_target in MMSPlugin.sdk_targets:
sdk = sdk_target.sdk
Expand Down
2 changes: 2 additions & 0 deletions CS2Fixes.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@
<ClCompile Include="src\detours.cpp" />
<ClCompile Include="src\gameconfig.cpp" />
<ClCompile Include="src\mempatch.cpp" />
<ClCompile Include="src\patches.cpp" />
<ClCompile Include="src\playermanager.cpp" />
<ClCompile Include="sdk\tier1\convar.cpp" />
<ClCompile Include="src\utils\entity.cpp" />
Expand Down Expand Up @@ -218,6 +219,7 @@
<ClInclude Include="src\gameconfig.h" />
<ClInclude Include="src\mempatch.h" />
<ClInclude Include="src\addresses.h" />
<ClCompile Include="src\patches.cpp" />
<ClInclude Include="src\playermanager.h" />
<ClInclude Include="src\recipientfilters.h" />
<ClInclude Include="src\serversideclient.h" />
Expand Down
78 changes: 65 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,84 @@
# RampbugFix
Minimizes rampbugs. This plugin isn't perfect and rampbugs will continue to occur until Valve decides to finally fix them.
# CSS-CS2Fixes

Fix taken from [CS2KZ's rampbug fix](https://gist.github.com/zer0k-z/2eb0c230c8f2c62b5c46d36353cf8d8d)
This plugin adds back some essential patches from CS2Fixes that are useful for surf servers.

- Minimizes rampbugs
- trigger_push fix
- Reverts trigger_push behaviour to that seen in CS:GO
- Water fix
- Fixes being stuck to the floor underwater, allowing players to swim up
- Navmesh lookup lag fix
- Some maps with built navmeshes would cause tremendous lag

This plugin isn't perfect and rampbugs will continue to occur until Valve decides to finally fix them.

Fixes taken from:
- [CS2Fixes](https://github.com/Source2ZE/CS2Fixes)
- [Cs2Fixes-Rampbugfix](https://github.com/Interesting-exe/CS2Fixes-RampbugFix)

## Installation

- Install [Metamod](https://cs2.poggu.me/metamod/installation/)
- Build the plugin using the [compilation instructions below](https://github.com/Interesting-exe/CS2Fixes-RampbugFix/tree/main?tab=readme-ov-file#instructions) or download the [latest release](https://github.com/Interesting-exe/CS2Fixes-RampbugFix/releases/latest)
- Download the [latest release package](https://github.com/Source2ZE/CS2Fixes/releases) for your OS
- Extract the package contents into `game/csgo` on your server

## Compilation

### Requirements
A guide on how to compile CS2-SurfFixes for Linux using VSCode and WSL.

- [Metamod:Source](https://www.sourcemm.net/downloads.php/?branch=master) (build 1219 or higher)
- [AMBuild](https://wiki.alliedmods.net/Ambuild)
#### Prerequisites
- [WSL](https://learn.microsoft.com/en-us/windows/wsl/install)
- [VSCode WSL Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl)
- [Git](https://git-scm.com/downloads)
- [Python3](https://www.python.org/downloads/)

### Instructions
**ALL PATHS ARE ASSUMED FOR EVERYTHING BEING PLACED IN THE /ROOT DIRECTORY**

Follow the instructions below to compile CS2Fixes.
#### File Structure
```bash
mkdir alliedmodders
cd alliedmodders
```

#### Ubuntu 20.04 setup
```bash
sudo apt update
sudo apt install python3-pip
sudo apt-get install clang

git clone https://github.com/Interesting-exe/CS2Fixes-RampbugFix && cd CS2Fixes-RampbugFix
git submodule update --init --recursive
# make sure we can use pip installed packages anywhere
echo "export PATH=\"$HOME/.local/bin:$PATH\"" >> ~/.bashrc
. ~/.bashrc
```

#### DownloadAMBuild
```bash
git clone https://github.com/alliedmodders/ambuild
pip install ./ambuild

export MMSOURCE112=/path/to/metamod/
export HL2SDKCS2=/path/to/sdk/submodule
# In case of an error try
# cd ambuild && python setup.py install && cd ..
```

#### Instructions
```bash
mkdir hl2sdk-root
git clone --branch cs2 https://github.com/alliedmodders/hl2sdk/ hl2sdk-root/hl2sdk-cs2
cd hl2sdk-root/hl2sdk-cs2
git checkout 74ea9343746475b148f5f53679516dc9cd2b336b

git clone https://github.com/alliedmodders/metamod-source --recursive
cd metamod-source

echo "export HL2SDKCS2=/root/alliedmodders/hl2sdk-root/hl2sdk-cs2" >> ~/.bashrc
echo "export MMSOURCE112=/root/alliedmodders/metamod-source/" >> ~/.bashrc
. ~/.bashrc
```

#### Plugin Compilation
```bash
git clone https://github.com/Fallen-Networks/CS2-SurfFixes && cd CS2-SurfFixes
git submodule update --init --recursive

mkdir build && cd build
python3 ../configure.py --enable-optimize --sdks cs2
Expand Down
39 changes: 37 additions & 2 deletions gamedata/cs2fixes.games.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,31 @@
"windows" "\x40\x55\x56\x57\x41\x54\x48\x8D\xAC\x24\x28\xFE\xFF\xFF"
"linux" "\x48\xB8\x00\x00\x00\x00\xFF\xFF\xFF\xFF\x55\x48\x89\xE5\x41\x57\x41\x89\xD7\x41\x56\x4C\x8D\xB5\x50"
}
"TriggerPush_Touch"
{
"library" "server"
"windows" "\x48\x89\x5C\x24\x2A\x48\x89\x7C\x24\x2A\x55\x48\x8D\xAC\x24\x2A\x2A\x2A\x2A\xB8\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x48\x2B\xE0\x48\x8B\x02\x48\x8B\xF9"
"linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x49\x89\xFC\x53\x48\x81\xEC\x2A\x2A\x2A\x2A\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\x41\x80\xBC\x24"
}
"SetGroundEntity"
{
"library" "server"
"windows" "\x48\x89\x5C\x24\x2A\x48\x89\x6C\x24\x2A\x56\x57\x41\x56\x48\x83\xEC\x2A\x33\xED\x4C\x89\x7C\x24"
"linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x55\x49\x89\xF5\x41\x54\x49\x89\xFC\x53\x48\x89\xD3\x48\x83\xEC\x2A\x8B\x97"
}
"CheckJumpButtonWater"
{
"library" "server"
"windows" "\xC8\x42\xEB\x2A\x48\x8B\x4B\x30"
"linux" "\xC8\x42\x66\x0F\xEF\xFF\x0F\x2F\x7B\x5C"
}
// String: "StartGravity", a function call in the function with startgravity in ends with "return (sub_XXX( a1 + 48) > 1);", change the 1 to 2
"WaterLevelGravity"
{
"library" "server"
"windows" "\x3C\x01\x49\x8B\x5B\x10\x49\x8B\x7B\x18\x0F\x97\xC0\x41\x0F\x28"
"linux" "\x3C\x01\x0F\x97\xC0\x48\x81\xC4\x50\x01"
}
// Function with 5 arguments next to sv_walkable_normal references
"TracePlayerBBox"
{
Expand Down Expand Up @@ -130,7 +155,7 @@
{
"library" "server"
"windows" "\x48\x89\x5C\x24\x2A\x48\x89\x54\x24\x2A\x48\x89\x4C\x24\x2A\x55\x56\x57\x41\x54\x41\x55\x41\x56\x41\x57\x48\x8D\xAC\x24\x2A\x2A\x2A\x2A"
"linux" "\x55\x48\x89\xE5\x41\x57\x41\x56\x41\x89\xCE\x41\x55\x49\x89\xFD\x41\x54\x48\x8D\x3D\x2A\x2A\x2A\x2A"
"linux" "\x55\x48\x89\xE5\x41\x57\x49\x89\xFF\x41\x56\x48\x8D\x3D\x2A\x2A\x2A\x2A\x41\x89\xCE"
}
// Search "Changes's player's model", look for a function containing 'models/%s.vmdl'. Below V_snprintf is the one
// This matches 2 functions on linux, however they're literally identical
Expand Down Expand Up @@ -314,7 +339,17 @@
}
}
"Patches"
{
{
"FixWaterFloorJump"
{
"windows" "\x11\x43"
"linux" "\x11\x43"
}
"WaterLevelGravity"
{
"windows" "\x3C\x02"
"linux" "\x3C\x02"
}
// Jumping over a check for nav mesh
"BotNavIgnore"
{
Expand Down
1 change: 1 addition & 0 deletions src/addresses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ bool addresses::Initialize(CGameConfig *g_GameConfig)
modules::hammer = new CModule(ROOTBIN, "tools/hammer");
#endif

RESOLVE_SIG(g_GameConfig, "SetGroundEntity", addresses::SetGroundEntity);
RESOLVE_SIG(g_GameConfig, "CBasePlayerController_SetPawn", addresses::CBasePlayerController_SetPawn);
RESOLVE_SIG(g_GameConfig, "InitPlayerMovementTraceFilter", addresses::InitPlayerMovementTraceFilter);
RESOLVE_SIG(g_GameConfig, "TracePlayerBBox", addresses::TracePlayerBBox);
Expand Down
2 changes: 1 addition & 1 deletion src/addresses.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ namespace addresses
bool Initialize(CGameConfig *g_GameConfig);

inline void(FASTCALL *CBasePlayerController_SetPawn)(CBasePlayerController *pController, CCSPlayerPawn *pPawn, bool a3, bool a4);

inline void(FASTCALL *SetGroundEntity)(Z_CBaseEntity *ent, Z_CBaseEntity *ground);
// typedef void InitPlayerMovementTraceFilter_t(CTraceFilterPlayerMovementCS &pFilter, CEntityInstance *pHandleEntity, uint64_t interactWith, int collisionGroup);
inline void(FASTCALL *InitPlayerMovementTraceFilter)(CTraceFilterPlayerMovementCS &pFilter, CEntityInstance *pHandleEntity, uint64_t interactWith, int collisionGroup);
// typedef void TracePlayerBBox_t(const Vector &start, const Vector &end, const bbox_t &bounds, CTraceFilterPlayerMovementCS *filter, trace_t_s2 &pm);
Expand Down
1 change: 1 addition & 0 deletions src/cs2fixes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "appframework/IAppSystem.h"
#include "common.h"
#include "detours.h"
#include "patches.h"
#include "icvar.h"
#include "interface.h"
#include "tier0/dbg.h"
Expand Down
1 change: 1 addition & 0 deletions src/detours.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "entity/ccsplayerpawn.h"
#include "entity/cbasemodelentity.h"
#include "entity/cgamerules.h"
#include "entity/ctriggerpush.h"
#include "entity/services.h"
#include "playermanager.h"
#include "igameevents.h"
Expand Down
6 changes: 4 additions & 2 deletions src/detours.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
#pragma once
#include "cdetour.h"


class CTriggerPush;
class CGameConfig;
class CCSPlayer_MovementServices;
class CMoveData;
Expand All @@ -31,4 +31,6 @@ void FlushAllDetours();

void FASTCALL Detour_ProcessMovement(CCSPlayer_MovementServices *pThis, void *pMove);
void FASTCALL Detour_TryPlayerMove(CCSPlayer_MovementServices *ms, CMoveData *mv, Vector *pFirstDest, trace_t *pFirstTrace);
void FASTCALL Detour_CategorizePosition(CCSPlayer_MovementServices *ms, CMoveData *mv, bool bStayOnGround);
void FASTCALL Detour_CategorizePosition(CCSPlayer_MovementServices *ms, CMoveData *mv, bool bStayOnGround);
void FASTCALL Detour_TriggerPush_Touch(CTriggerPush* pPush, Z_CBaseEntity* pOther);
void* FASTCALL Detour_CNavMesh_GetNearestNavArea(int64_t unk1, float* unk2, unsigned int* unk3, unsigned int unk4, int64_t unk5, int64_t unk6, float unk7, int64_t unk8);
47 changes: 47 additions & 0 deletions src/mempatch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,53 @@ bool CMemPatch::PerformPatch(CGameConfig *gameConfig)
return true;
}


bool CMemPatch::PerformPatchTest(CGameConfig* gameConfig)
{
// We're patched already
if (m_pOriginalBytes)
return true;

// If we already have an address, no need to look for it again
if (!m_pPatchAddress)
{
m_pPatchAddress = (uintptr_t)gameConfig->ResolveSignature(m_pSignatureName);

if (!m_pPatchAddress)
return false;
}

const char* patch = gameConfig->GetPatch(m_pszName);
if (!patch)
{
Panic("Failed to find patch for %s\n", m_pszName);
return false;
}
m_pPatch = gameConfig->HexToByte(patch, m_iPatchLength);
if (!m_pPatch)
return false;

if (V_strcmp(m_pOffsetName, ""))
{
m_iOffset = gameConfig->GetOffset(m_pOffsetName);
if (m_iOffset == -1)
{
Panic("Failed to find offset %s for patch %s\n", m_pOffsetName, m_pszName);
return false;
}

m_pPatchAddress += m_iOffset;
}

m_pOriginalBytes = new byte[m_iPatchLength];
V_memcpy(m_pOriginalBytes, (void*)m_pPatchAddress, m_iPatchLength);

Plat_WriteMemory((void*)m_pPatchAddress, (byte*)m_pPatch, m_iPatchLength);

Message("Patched %s at %p\n", m_pszName, m_pPatchAddress);
return true;
}

void CMemPatch::UndoPatch()
{
if (!m_pPatchAddress)
Expand Down
2 changes: 1 addition & 1 deletion src/mempatch.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class CMemPatch
m_iPatchLength = 0;
m_iOffset = 0;
}

bool PerformPatchTest(CGameConfig *gameConfig);
bool PerformPatch(CGameConfig *gameConfig);
void UndoPatch();

Expand Down
60 changes: 60 additions & 0 deletions src/patches.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* =============================================================================
* CS2Fixes
* Copyright (C) 2023-2025 Source2ZE
* =============================================================================
*
* 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/>.
*/

#include "patches.h"
#include "addresses.h"
#include "common.h"
#include "icvar.h"
#include "irecipientfilter.h"
#include "mempatch.h"

#include "tier0/memdbgon.h"

extern CGameConfig* g_GameConfig;

CMemPatch g_CommonPatches[] =
{
CMemPatch("CheckJumpButtonWater", "FixWaterFloorJump"),
CMemPatch("WaterLevelGravity", "WaterLevelGravity"),
CMemPatch("BotNavIgnore", "BotNavIgnore"),
#ifndef _WIN32
// Linux checks for the nav mesh in each bot_add command, so we patch 3 times
CMemPatch("BotNavIgnore", "BotNavIgnore"),
CMemPatch("BotNavIgnore", "BotNavIgnore"),
#endif
};


bool InitPatches(CGameConfig* g_GameConfig)
{
bool success = true;

// Skip first patch (movement unlocker), it gets patched in convar callback
for (int i = 01; i < sizeof(g_CommonPatches) / sizeof(*g_CommonPatches); i++)
if (!g_CommonPatches[i].PerformPatchTest(g_GameConfig))
success = false;

return success;
}

void UndoPatches()
{
for (int i = 0; i < sizeof(g_CommonPatches) / sizeof(*g_CommonPatches); i++)
g_CommonPatches[i].UndoPatch();
}
Loading