Xrasher

Recently, I concluded a pet project that I would occasionally work on. It was a ‘cheat’ that worked universally for the ‘Xash3D’ engine, an-almost-clean-room-but-not-quite reimplementation of the proprietary GoldSRC engine. I embarked on this project when I was writing a multiplayer protocol in C, to scratch some itches and to test out certain thought experiments. The result was quite successful, much more than I anticipated. You can browse the source on my software forge. I thought to myself that I would modify the engine’s source itself.

Aim Assistance

The aim-assist in Xrasher works by modifying a networking ‘usercmd message’ almost immediately before it is sent to the server in the input gathering portion of engine/client/input.c (specifically, the IN_EngineAppendMove function), the following is the structure of such message.

typedef struct usercmd_s
{
    short             lerp_msec;     // Interpolation time on client
    byte              msec;          // Duration in ms of command
    vec3_t            viewangles;    // Command view angles

    // intended velocities
    float             forwardmove;     // Forward velocity
    float             sidemove;        // Sideways velocity
    float             upmove;          // Upward velocity
    byte              lightlevel;      // Light level at spot where we are standing.
    unsigned short    buttons;         // Attack and move buttons
    byte              impulse;         // Impulse command issued
    byte              weaponselect;    // Current weapon id

    // Experimental player impact stuff.
    int               impact_index;
    vec3_t            impact_position;
} usercmd_t;

The viewangles of the player can be changed instantaneously to any position on the client-side, there is some ramifications to writing an aim-assist that does this, you can’t visibly see how other players perceive you or what direction the aim-assist is making you aim. This sort of circumvents a lot of client-side effects as well, so when shooting a firearm, you would see bullet decals in front of you, regardless of the fact the server believes you are aiming in a completely different direction. It would be ideal to implement some sort of UI elements to assist with this. Early on when writing the aim-assist, I chose the dumbest possible implementation, just to see if it was feasible to implement in this certain way. When a key was toggled, aim at the physically closest player. It worked, but it was very
clunky and unreliable, movement was difficult and you would be bumping into walls. I discovered a few simple principles that are critical to the usability of an aim-assist.

1. Only activate if the left or right mouse button is held-down.
2. Lock onto targets in regards to angular distance not physical distance.
3. Have a maximum angular distance for locking, to cull out irrelevant entities.
4. (I didn’t do this) Only lock onto players that are visible.

Aim Assistance Algorithm

void CL_XrasherAim(usercmd_t* cmd){
    vec3_t aimDirection, targetAngles;
    cl_entity_t* localPlayer = CL_GetLocalPlayer();
    cl_entity_t* nearestTarget = NULL;
    float minAngleDifference = xrasher_maxdist.value;
    vec3_t currentAngles = { cmd->viewangles[0], cmd->viewangles[1], 0 };
    float angleDifference;

    for (int i = 0; i < CL_GetMaxClients(); ++i){
        cl_entity_t *ent = CL_GetEntityByIndex(i);
        if (!ent || ent == localPlayer || ent->player != true ) continue;

        VectorSubtract(ent->origin, localPlayer->origin, aimDirection);
        VectorAngles(aimDirection, targetAngles);

        angleDifference = fabsf(targetAngles[0] - currentAngles[0]) + fabsf(targetAngles[1] - currentAngles[1]);

        if ((angleDifference < minAngleDifference)){
            minAngleDifference = angleDifference;
            nearestTarget = ent;
        }
    }

    if (nearestTarget){
        vec3_t aimDirection, targetAngles;
        VectorSubtract(nearestTarget->origin, localPlayer->origin, aimDirection);
        VectorAngles(aimDirection, targetAngles);

       // Normalize pitch (aimDirection[0]) and yaw (aimDirection[1]) to -180 to 180 range
       aimDirection[0] = fmodf(aimDirection[0] + 180.0f, 360.0f);
       if (aimDirection[0] < 0) aimDirection[0] += 360.0f;
       aimDirection[0] -= 180.0f;
       aimDirection[1] = fmodf(aimDirection[1] + 180.0f, 360.0f);
       if (aimDirection[1] < 0) aimDirection[1] += 360.0f;
       aimDirection[1] -= 180.0f;


        // Apply aim assist by modifying the player's input angles
        cmd->viewangles[0] = targetAngles[0]; // Pitch
        cmd->viewangles[1] = targetAngles[1]; // Yaw

       Con_Print("FOUND TARGET\n");
       return;

    }

    Con_Print("NO TARGET\n");
}

Wallhack Implementation

Xash3D-FWGS has two renderer implementations, one OpenGL renderer, and one software-renderer (SW), in order to implement a wallhack, I decided to modify how the renderer rendered dynamic meshes in the world, these are referred to as “studiomodels”, in Xash, the world is usually built from brush level geometry, while the things that move around, like players, or pickups, are studio models. It was substantially easier to implement the wallhack for the OpenGL renderer, you simply just render another pass with no depth testing, and just like that you see things through walls. In regards to the software-renderer, it was more complicated, and to this day it is still non-functional in practice, I was modifying the ‘scanning’ portion of the rasterization process. It worked, sometimes, but very often models ‘obscure’ each other, and things become invisible. Specifically you are working with ‘rendering spans’, it is an optimization technique where you render strips of pixels at a time, rather than pixel by pixel. I probably would not implement a SW renderer like this, and I believe this is some legacy inheritance from Quake.

Automatic Ban Evasion

In Xash3D_FWGS, the maintainers added a “XashID” system, an attempt at Hardware identification, this is handled in the engine/client/identification.c file. The objective is to allow server administrators to ban users that have identical hardware. What Xash does is that it scans information about your hardware and with that creates a new ID based on an MD5 hash. All you have to do to circumvent this, is to just modify the engine to fraudulently create new IDs irrespective of your hardware, it is completely clientside, I made Xrasher generate a new one every startup. I didn’t think I would ever need to use this capability, but it was interesting to overcome such a system in such a messy way. This however does not account for IP bans, I had the assumption that XashID bans would be the initial response, of course if you are joining GoldSRC servers, the XashID system is completely irrelevant, and all bans are based on IP addresses and/or a St*am auth token.

Links, References, and Resources

github.com/rehlds/ReGameDLL_CS/
github.com/FWGS/xash3d-fwgs/
github.com/Velaron/cs16-client