Yelo: Halo 2 Xbox Trainer


Here’s the first of a few older projects I’ll end up posting and open sourcing on this site just for historical purposes. The Halo games and Xbox console in general are what originally got me involved in software development, so I figure I’ll post what started it all first.

It began in December of 2004 with me installing a mod-chip on my Xbox which basically turns it into a media center and also allows for the execution of homebrew software among other things. During that process, I stumbled across the Halo 2 map editor Ch2r, which provided the basic ability to open Halo 2 .map files and modify the resources within. Halo maps use a tag-based system for storing information related to everything from vehicle and weapon settings to particle effects or raw resources such as models, images, and sounds. Ch2r had an xml plugin system that was used to identify offsets and data types of the information stored in each of those tags. Since most plugins were still in their infancy, I decided to teach my self how to read the tags extracted by Ch2r in a hex editor and identify some of the tag values for the rest of the Halo modding community to use in their mods.

Eventually, I became interested in the Halo 2 game engine itself, and started learning x86 assembly so I could make a simple third person camera hack similar to the one bitterbanana made for the original Halo on PC. With the help of Acidflash, EvoxT, and a few others in the scene, I started picking up the knowledge needed to create and inject assembly code into Xbox games. On and off over the course of a few years, I spent lots of time researching the Halo 2 game engine by locating things in memory, stepping through the code in a debugger, studying its disassembly, and documenting all of my findings. The features in Yelo are only a small collection of the things I’ve found researching throughout the years, but it still provides users with plenty of options and a good overall summary of some of the useful things that can be done in the game. Bungie must have also recognized the large amount of replay value these kinds of features offer, since they’ve included something similar to Yelo in all of their new titles following Halo 2, allowing you to fly around in the levels and take screen shots. I only wish other game developers in the industry would catch on and do the same, as exploring some of these virtual worlds can be very fun and interesting.

If you don’t know how to use trainers (hell, I barely remember anymore :P), I suggest you check out Xbox-Scene or MaxConsole for further information. Along with the trainer, you must also transfer over the “config_v1.5.inc” file to “E:/TDATA/4D530064/”. If you fail to do so the trainer will not function properly and immediately go into wireframe at the press of a button. Every combo and a few other options can be edited via the trainer config file. Note that some of the cinematic and lighting options are experimental so if you don’t like them, don’t use them :P

This trainer will only work with the Xored ETM Launcher v2.2 (due to memory allocation issues) so be sure to download that before use. Please use Aequitas’ UberScreenshotTool below for screenshot recovery. Use the supplied config editor below if you wish to change things. For those of you that have been complaining about the 1.1 update and wish to still use the new maps, download and apply Snave’s mainmenu patch below.

Configuration:
============
dpad-up = increase cam speed*
dpad-down = decrease cam speed*
dpad-left = decrease look speed*
dpad-right = increase look speed*
lthumb+rthumb = toggle timefreeze
lthumb+dpad-up = increase vertical look shift
lthumb+dpad-down = decrease vertical look shift
lthumb+dpad-left = increase horizontal look shift
lthumb+dpad-right = decrease horizontal look shift
lthumb+black = disable cinematic mode
lthumb+white = enable cinematic mode
lthumb+back = stillcam
rthumb+dpad-up = decrease camera depth
rthumb+dpad-down = increase camera depth
rthumb+dpad-left = increase fov
rthumb+dpad-right = decrease fov
rthumb+A = save camera state (shifts, fov, and depth)
rthumb+B = load camera state (shifts, fov, and depth)
rthumb+X = save gamestate
rthumb+Y = load gamestate
rthumb+back = cutscene camera
back+dpad-up = first person perspective
back+dpad-down = third person perspective
back+dpad-left = chasecam perspective
back+dpad-right = devcam perspective
black+dpad-up = increase z cam shift
black+dpad-down = decrease z cam shift
black+dpad-left = decrease y cam shift
black+dpad-right = increase y cam shift
white+dpad-down = auto hires grabber*
white+dpad-left = vidcap (10fps)
white+dpad-right = 360 degree shot*
white+back = screenshot
rtrigger = move up along z axis*
ltrigger = move down along z axis*
A+dpad-up = letterbox toggle
A+dpad-down = wireframe
A+dpad-left = hud toggle
A+dpad-right = ai toggle
A+black = decrease ambient light brightness
A+white = increase ambient light brightness
B+dpad-up = teleport to current camera coordinates
B+dpad-left = decrease gamespeed
B+dpad-right = increase gamespeed
X+dpad-up = secondary light vertical increase
X+dpad-down = secondary light vertical decrease
X+dpad-left = secondary light horizontal decrease
X+dpad-right = secondary light horizontal increase
X+black = decrease secondary light brightness
X+white = increase secondary light brightness
Y+dpad-up = primary light vertical increase
Y+dpad-down = primary light vertical decrease
Y+dpad-left = primary light horizontal decrease
Y+dpad-right = primary light horizontal increase
Y+black = decrease primary light brightness
Y+white = increase primary light brightness

* while in devcam

Checklist:
=========
-Have you read this entire post?
-Are you using the Xored v2.2 launcher with correct config settings?
-Did you transfer over the “config_v1.5.inc” to “E:/TDATA/4D530064/”?
-Did you disable the Autoupdate in your trainer options menu?
-Do you only have one controller plugged in, and is it in the first controller port?
-Do you have a semi-functional brain that posesses the knowledge required to run such a fine piece of software?

Downloads
Yelo: Halo 2 Xbox Trainer (1472)
Yelo Config Editor (1298)
Snave's Main Menu Patch (1230)
UberScreenshotTool (1114)

Optimized C# Halo 2 Map Signing Algorithm

I was working on an efficient map modification library and figured that this could benefit lots of other people. This small optimization lesson will walk you through different variations of the same snippet of code, each one more optimal than the last, ultimately leading to huge benefits in performance.

For those of you who are unfamiliar with the Halo 2 map format, every map file contains a 32 bit hash 720 bytes into the header, which allows the game engine to detect any modifications that have been made to the map. They do this by scanning the map file during initialization and XORing every integer after the map header and comparing their result with the hash. If they do not match, the level will “fail to load”.

For starters, we will be looking at this basic signing algorithm that I see is used quite frequently among the community. Some of these examples below assume 16-byte alignment for the map size, although the game requires much more than that in order to properly load, so these assumptions should be fair ones to make. Benchmarks were performed by executing an optimized release build outside of the debugger, although you will most likely see different results depending on your particular setup. Please also keep in mind that you will need to slightly modify these code samples to use your own information, instead of my MapHeader.SizeOf, Header.FileSize, Header.Signature, and Stream stuff…but you get the idea ;)

public void Sign()
{
    // initial declarations
    uint checksum = 0;
    Stream.Position = MapHeader.SizeOf;

    // loop through the map hashing one integer at a time
    for (int i = 0; i < Header.FileSize - MapHeader.SizeOf; i += 4)
        checksum ^= Stream.ReadUInt32();

    // save the final signature
    Header.Signature = checksum;
}

As you can see, it starts reading data after the header and XORing one integer at a time until the end of the map is reached.

Some of you may now be thinking, “well how much more efficient can you get than that? It is just a simple XOR of each integer after all…” To answer that question, you will need to understand a little more about what is going on behind the scenes. Every operation, you access the file (SLOW), update the checksum, compute the hash range size, check if its finished, and branch accordingly. The main performance killer here is too much file IO, although the others can and do slightly affect the performance as well.

So first off, how do we minimize the amount of file accesses? We will start to buffer our reads. The trick here is to pick a buffer big enough to decrease the amount of file accesses, yet small enough to not thrash the CPU cache when working with the larger amount of data. For these reasons, I chose a moderately sized buffer of 64 kilobytes. If you have newer hardware it may be more beneficial to increase this size even further, depending on your HDD and CPU cache sizes. With these facts in mind, here is our new result…

public void Sign()
{
    // initial declarations
    uint checksum = 0;
    int blockSize = 0x10000;    // 64kb
    byte[] block = new byte[blockSize];
    int hashSize = (int)(Header.FileSize - MapHeader.SizeOf);
    int fullPassses = hashSize / blockSize;
    int remainder = hashSize % blockSize;
    Stream.Position = MapHeader.SizeOf;

    // loop through the map hashing one full block at a time
    for (int i = 0; i < fullPassses; i++)
    {
        Stream.Read(block, 0, blockSize);
        for (int j = 0; j < blockSize; j += 4)
            checksum ^= BitConverter.ToUInt32(block, j);
    }

    // hash the remainder
    Stream.Read(block, 0, remainder);
    for (int j = 0; j < remainder; j += 4)
        checksum ^= BitConverter.ToUInt32(block, j);

    // save the final signature
    Header.Signature = checksum;
}

Just by blocking your file IO, you can obtain a dramatic increase in performance. This algorithm should outperform the other one above by being at least 6 times faster.

To push our performance gains even further, instead of calling BitConverter.ToUInt32() thousands of times introducing lots of unneeded overhead, we can try dealing with the data on a much lower level by using unsafe code. Working with pointers and fixed buffers allow us to speed things up even further as demonstrated by this next piece of code.

unsafe public void Sign()
{
    // initial declarations
    uint checksum = 0;
    int blockSize = 0x10000;    // 64kb
    byte[] block = new byte[blockSize];
    int hashSize = (int)(Header.FileSize - MapHeader.SizeOf);
    int fullPassses = hashSize / blockSize;
    int blockPasses = blockSize / 4;
    int remainder = hashSize % blockSize;
    int remainingPasses = remainder / 4;
    Stream.Position = MapHeader.SizeOf;

    fixed (byte* buf = &block[0])
    {
        uint* p = (uint*)buf;

        // loop through the map hashing one full block at a time
        for (int i = 0; i < fullPassses; i++)
        {
            Stream.Read(block, 0, blockSize);
            for (int j = 0; j < blockPasses; j++)
                checksum ^= p[j];
        }

        // hash the remainder
        Stream.Read(block, 0, remainder);
        for (int j = 0; j < remainingPasses; j++)
            checksum ^= p[j];

        // save the final signature
        Header.Signature = checksum;
    }
}

Here, I’m seeing performance gains around 11 times faster than the original form. Not too shabby, but still, more can be done to help speed things up even further. This last technique is commonly referred to as loop unrolling, which will help to decrease some of the loop overhead, and can become quite beneficial in small tighter loops such as these.

unsafe public void Sign()
{
    // initial declarations
    uint checksum = 0;
    int blockSize = 0x10000;    // 64kb
    byte[] block = new byte[blockSize];
    int hashSize = (int)(Header.FileSize - MapHeader.SizeOf);
    int blockCount = hashSize / blockSize;
    int blockPasses = blockSize / 16;
    int remainder = hashSize % blockSize;
    int remainingPasses = remainder / 16;
    Stream.Position = MapHeader.SizeOf;

    fixed (byte* buf = &block[0])
    {
        // loop through the map hashing one full block at a time
        uint* p;
        for (int i = 0; i < blockCount; i++)
        {
            p = (uint*)buf;
            Stream.Read(block, 0, blockSize);
            for (int j = 0; j < blockPasses; j++)
            {
                checksum ^= p[0];
                checksum ^= p[1];
                checksum ^= p[2];
                checksum ^= p[3];
                p += 4;
            }
        }

        // hash the remainder
        p = (uint*)buf;
        Stream.Read(block, 0, remainder);
        for (int j = 0; j < remainingPasses; j++)
        {
            checksum ^= p[0];
            checksum ^= p[1];
            checksum ^= p[2];
            checksum ^= p[3];
            p += 4;
        }

        // save the final signature
        Header.Signature = checksum;
    }
}

This one clocks in at being around 23 times faster than our original algorithm…can’t get much better than that without delving into c++ and harnessing the power of SIMD and assembly.

Many of these optimization practices are not limited to just this algorithm, but can be used in many different situations, and are capable of producing much more efficient code at the unfortunate expense of decreased readability. Through buffered IO, unsafe code, loop unrolling, and other minor optimizations, we were able to increase the performance of our generic piece of code making it 20 times faster.

Now, these types of optimizations should really only be done after properly profiling your application to determine where it spends the most of its time, and this was more or less just a lesson on some of the optimization techniques you have at your disposal when required to do so.

Yelo: Halo 1 Xbox Trainer

The first of many revisions planned for Halo 1 (xbox). Let me know if this won’t load or something else weird happens. I’ve only spent a total of two days working on this so don’t expect wonders…it’s not the easiest thing to port :P

Instructions:
———————-
1.) Place the Resource.rsrc file in your ‘E:TDATA4D530004′ folder
2.) Run YeloH1.etm with a trainer launcher (xored or evox)
3.) Cross fingers and hope for the best :P

Updates:
———————-
10/22/07 – v1.1 – still not stable by any means, just a quick port to hold you over…

Controls:
———————-
IGK_FirstPerson dw GAMEPAD_BACK + GAMEPAD_DPAD_UP
IGK_ThirdPerson dw GAMEPAD_BACK + GAMEPAD_DPAD_DOWN
IGK_DevCam dw GAMEPAD_BACK + GAMEPAD_DPAD_RIGHT
IGK_SpectatorCam dw GAMEPAD_BACK + GAMEPAD_DPAD_LEFT
IGK_ScriptedCam dw GAMEPAD_RIGHT_THUMB + GAMEPAD_BACK
IGK_StillCam dw GAMEPAD_LEFT_THUMB + GAMEPAD_BACK
IGK_IncreaseLookSpeed dw GAMEPAD_A + GAMEPAD_DPAD_RIGHT
IGK_DecreaseLookSpeed dw GAMEPAD_A + GAMEPAD_DPAD_LEFT
IGK_IncreaseMoveSpeed dw GAMEPAD_A + GAMEPAD_DPAD_UP
IGK_DecreaseMoveSpeed dw GAMEPAD_A + GAMEPAD_DPAD_DOWN
IGK_IncreaseGameSpeed dw GAMEPAD_WHITE + GAMEPAD_DPAD_RIGHT
IGK_DecreaseGameSpeed dw GAMEPAD_WHITE + GAMEPAD_DPAD_LEFT
IGK_IncreaseHCamShift dw GAMEPAD_BLACK + GAMEPAD_DPAD_RIGHT
IGK_DecreaseHCamShift dw GAMEPAD_BLACK + GAMEPAD_DPAD_LEFT
IGK_IncreaseVCamShift dw GAMEPAD_BLACK + GAMEPAD_DPAD_UP
IGK_DecreaseVCamShift dw GAMEPAD_BLACK + GAMEPAD_DPAD_DOWN
IGK_IncreaseCamDepth dw GAMEPAD_RIGHT_THUMB + GAMEPAD_DPAD_DOWN
IGK_DecreaseCamDepth dw GAMEPAD_RIGHT_THUMB + GAMEPAD_DPAD_UP
IGK_IncreaseFOV dw GAMEPAD_RIGHT_THUMB + GAMEPAD_DPAD_LEFT
IGK_DecreaseFOV dw GAMEPAD_RIGHT_THUMB + GAMEPAD_DPAD_RIGHT
IGK_WireFrame dw GAMEPAD_B + GAMEPAD_DPAD_DOWN
IGK_ScreenShot dw GAMEPAD_WHITE + GAMEPAD_DPAD_UP
IGK_TimeFreeze dw GAMEPAD_RIGHT_THUMB + GAMEPAD_LEFT_THUMB
IGK_Teleport dw GAMEPAD_B + GAMEPAD_DPAD_UP
IGK_AllWeapons dw GAMEPAD_B + GAMEPAD_DPAD_RIGHT
IGK_DumpDebugInfo dw GAMEPAD_LEFT_THUMB + GAMEPAD_B + GAMEPAD_Y
IGK_AllPowerups dw GAMEPAD_B + GAMEPAD_DPAD_LEFT
IGK_AllVehicles dw GAMEPAD_Y + GAMEPAD_DPAD_LEFT
IGK_AIEraseAll dw GAMEPAD_Y + GAMEPAD_DPAD_RIGHT
IGK_GameWon dw GAMEPAD_Y + GAMEPAD_DPAD_UP
IGK_ActiveCamo dw GAMEPAD_Y + GAMEPAD_DPAD_DOWN
IGK_BumpPosession dw GAMEPAD_RIGHT_THUMB + GAMEPAD_A
IGK_Invincibility dw GAMEPAD_RIGHT_THUMB + GAMEPAD_B
IGK_InfiniteAmmo dw GAMEPAD_RIGHT_THUMB + GAMEPAD_X
IGK_InfiniteGrenades dw GAMEPAD_RIGHT_THUMB + GAMEPAD_Y
IGK_SaveGameState dw GAMEPAD_X + GAMEPAD_DPAD_LEFT
IGK_LoadGameState dw GAMEPAD_X + GAMEPAD_DPAD_RIGHT
IGK_HudToggle dw GAMEPAD_X + GAMEPAD_DPAD_UP
IGK_LetterboxToggle dw GAMEPAD_X + GAMEPAD_DPAD_DOWN

Download
Yelo: Halo 1 Xbox Trainer (1335)