initial commit -- v1 code
This commit is contained in:
178
README.md
Normal file
178
README.md
Normal file
@@ -0,0 +1,178 @@
|
||||
# SendProxy for CS2
|
||||
|
||||
SendProxy is an experimental Counter-Strike 2 Metamod addon plus CounterStrikeSharp interop layer for per-recipient networked field spoofing.
|
||||
|
||||
The goal is similar to Source 1 `SendProxy`: let plugin code change the value serialized to one viewer without changing the real server entity state. For example, player A can see an entity field as one value while player B sees another value.
|
||||
|
||||
## Current Architecture
|
||||
|
||||
The Metamod addon is intentionally small:
|
||||
|
||||
- Hooks `CServerSideClient::SendSnapshot` to identify the recipient slot for the current snapshot.
|
||||
- Hooks `CNetworkGameServer::PackEntity`.
|
||||
- Looks up exact rules by packed entity index.
|
||||
- Temporarily writes raw bytes to the entity field.
|
||||
- Calls the original entity packer.
|
||||
- Restores the original bytes immediately.
|
||||
|
||||
There is no value parser or high-level rule language in Metamod. CounterStrikeSharp owns typed values, selectors, policy, and rule lifecycle.
|
||||
|
||||
Native rule shape:
|
||||
|
||||
```text
|
||||
recipient slot + entity index + schema field path = raw bytes
|
||||
```
|
||||
|
||||
The native side resolves `className + fieldPath` to a schema offset when a rule is added. The pack hot path does not parse strings, walk entities, or query schema.
|
||||
|
||||
## Native ABI
|
||||
|
||||
The addon exports a small C ABI from `sendproxy.so`:
|
||||
|
||||
```cpp
|
||||
extern "C" int SendProxy_SetOverride(
|
||||
int recipientSlot,
|
||||
int entityIndex,
|
||||
const char* className,
|
||||
const char* fieldPath,
|
||||
const void* value,
|
||||
int valueSize);
|
||||
|
||||
extern "C" bool SendProxy_RemoveOverride(int ruleId);
|
||||
extern "C" void SendProxy_ClearOverrides();
|
||||
extern "C" bool SendProxy_MarkDirty(int entityIndex, const char* className, const char* fieldPath);
|
||||
```
|
||||
|
||||
`recipientSlot` may be `-1` for all recipients, or `0..63` for one viewer.
|
||||
|
||||
`SendProxy_SetOverride` returns a rule ID. Keep this ID in managed code and pass it to `SendProxy_RemoveOverride` when the spoof is no longer wanted.
|
||||
|
||||
Disabled native rules are compacted on every map start.
|
||||
|
||||
## CounterStrikeSharp Wrapper
|
||||
|
||||
The C# wrapper is in:
|
||||
|
||||
```text
|
||||
examples/CounterStrikeSharp/SendProxyNative.cs
|
||||
```
|
||||
|
||||
It loads the native addon with `NativeLibrary.Load` and exposes byte-oriented and typed helpers. In a CSS plugin, resolve the native library from the normal addons layout:
|
||||
|
||||
```csharp
|
||||
string addonsDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, "..", "..", ".."));
|
||||
string libraryPath = Path.Combine(addonsDirectory, "sendproxy", "bin", "linuxsteamrt64", "sendproxy.so");
|
||||
var sendProxy = new SendProxyNative(libraryPath);
|
||||
|
||||
int ruleId = sendProxy.SetInt32(
|
||||
recipientSlot: viewer.Slot,
|
||||
entityIndex: (int)targetPawn.Index,
|
||||
className: "CBaseEntity",
|
||||
fieldPath: "m_iHealth",
|
||||
value: 42);
|
||||
|
||||
sendProxy.RemoveOverride(ruleId);
|
||||
```
|
||||
|
||||
Use `SetBytes` for custom/fixed-layout fields and typed helpers such as `SetInt32`, `SetUInt32`, `SetFloat`, `SetBool`, and `SetColor` for common values.
|
||||
|
||||
## Example CSS Plugin
|
||||
|
||||
Example source:
|
||||
|
||||
```text
|
||||
examples/CounterStrikeSharp/SendProxyWeaponVisibility/
|
||||
```
|
||||
|
||||
It demonstrates:
|
||||
|
||||
- Spoofing other players' pawn health to `42` per viewer while leaving the viewer's own health real.
|
||||
- Hiding weapon entities owned by other players with spoofed `CBaseEntity::m_fEffects`.
|
||||
- Coloring dropped AK-47s red for Terrorist viewers.
|
||||
- Coloring dropped M4A1-S blue for CT viewers.
|
||||
|
||||
This sample periodically reconciles desired rules and diffs them against active rule IDs. For production, prefer event-driven updates on player connect/disconnect/team changes/spawn/death and weapon pickup/drop/create/delete.
|
||||
|
||||
## Building the Metamod Addon
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- AMBuild 2.2+
|
||||
- Metamod:Source
|
||||
- HL2SDK for CS2
|
||||
- `funchook` and generated protobuf headers as referenced by `AMBuildScript`
|
||||
|
||||
The defaults in `configure.py` match this workspace:
|
||||
|
||||
```text
|
||||
--hl2sdk-root /home/csgo/am/hl2sdk-root
|
||||
--mms_path /home/csgo/am/metamod-source
|
||||
```
|
||||
|
||||
Configure and build:
|
||||
|
||||
```bash
|
||||
mkdir -p build
|
||||
cd build
|
||||
python3 ../configure.py --enable-debug
|
||||
ambuild
|
||||
```
|
||||
|
||||
The packaged addon is written to:
|
||||
|
||||
```text
|
||||
build/package/addons/sendproxy/
|
||||
build/package/addons/metamod/sendproxy.vdf
|
||||
```
|
||||
|
||||
## Installing
|
||||
|
||||
Copy the package into the CS2 server's `game/csgo/addons` tree:
|
||||
|
||||
```bash
|
||||
cp -a build/package/addons/sendproxy /home/csgo/serverfiles/game/csgo/addons/
|
||||
cp -a build/package/addons/metamod/sendproxy.vdf /home/csgo/serverfiles/game/csgo/addons/metamod/
|
||||
```
|
||||
|
||||
In this workspace, `/home/csgo/codex/sendproxy/serverfiles` is a bind-mounted target equivalent to `/home/csgo/serverfiles`.
|
||||
|
||||
Verify the native ABI exports:
|
||||
|
||||
```bash
|
||||
nm -D /home/csgo/serverfiles/game/csgo/addons/sendproxy/bin/linuxsteamrt64/sendproxy.so \
|
||||
| rg 'SendProxy_(SetOverride|RemoveOverride|ClearOverrides|MarkDirty)'
|
||||
```
|
||||
|
||||
## Building the CSS Example
|
||||
|
||||
This container currently has the CounterStrikeSharp .NET runtime but not a .NET SDK, so the C# sample cannot be compiled here as-is.
|
||||
|
||||
On a machine with the .NET SDK:
|
||||
|
||||
```bash
|
||||
cd examples/CounterStrikeSharp/SendProxyWeaponVisibility
|
||||
dotnet build -c Release
|
||||
```
|
||||
|
||||
Install the built CSS plugin under:
|
||||
|
||||
```text
|
||||
game/csgo/addons/counterstrikesharp/plugins/SendProxyWeaponVisibility/
|
||||
```
|
||||
|
||||
Make sure `SendProxyNative.cs` is included in your CSS project or copied into your plugin source.
|
||||
|
||||
The example plugin expects the Metamod addon at:
|
||||
|
||||
```text
|
||||
game/csgo/addons/sendproxy/bin/linuxsteamrt64/sendproxy.so
|
||||
```
|
||||
|
||||
## Notes and Limits
|
||||
|
||||
- Only fields serialized through the hooked `PackEntity` path are affected.
|
||||
- The real server entity state is restored immediately after packing.
|
||||
- The value byte layout must match the server schema field layout.
|
||||
- The native addon validates that `valueSize` is not larger than the resolved schema field size when schema size is available.
|
||||
- Rule updates should be event-driven where possible. Avoid removing and recreating many rules every tick.
|
||||
- If per-entity rule lists become large, the next native optimization is indexing by `(entityIndex, recipientSlot)` instead of only `entityIndex`.
|
||||
Reference in New Issue
Block a user