I'll answer this question, though it may be a bit confusing, so bear with me. Also, The Cheat will not really be that practical to use as you can't easily tell it, "give me the value of the variable at this address." Lastly, this is a newbie's warning, but you need to be the host if you want to change player's locations
I'm going to be referencing this page a bit in my post:
http://www.modacity.net/forums/showthre ... Structures
Also, I'm going to make this post in such a way that it's helpful if you know how to use
my memory modding tool or that it's helpful if you want to learn how to use it (as The Cheat will probably not be sufficient enough [as I've already mentioned] for doing this anyway).
Halo has two structures for players. One is a static structure and the other is a dynamic structure. The static structure has some stuff like the player's name and what team he is on. The dynamic structure has stuff like player location, heath, rotation. The static structure is always static [constant] in memory. The dynamic structure is destroyed and re-created, say, every time the player dies (or a new game begins). So, if you happen to grab the player's location values in The Cheat in a particular instance, it'll only apply if the structure is not re-created, unless if you know how to re-calculate the location addresses which is what I'll get into.
The static player structure looks something like this:
Code: Select all
struct Static_Player
{
unsigned short PlayerID; // Stats at 0x70EC
unsigned short PlayerID2; // ???
wchar_t PlayerName0[12]; // Unicode / Max - 11 Chars + EOS (12 total)
long Unknown0; // Always -1 / 0xFFFFFFFF
unsigned long Team; // 0 = Red / 1 = Blue
unsigned long SwapID; // ObjectID
unsigned short SwapType; // 8 = Vehicle / 6 = Weapon
short SwapSeat; // Warthog - Driver = 0 / Passenger = 1 / Gunner = 2 / Weapon = -1
unsigned long RespawnTimer; // ?????? Counts down when dead, Alive = 0
unsigned long Unknown1; // Always 0
unsigned short ObjectIndexNum;
unsigned short ObjectID; // Matches against object table
unsigned long Unknown3; // Some sort of ID
unsigned long LocationID; // This is very, very interesting. BG is split into 25 location ID's. 1 -19
long Unknown4; // Always -1 / 0xFFFFFFFF
unsigned long BulletCount; // Something to do with bullets increases - weird.
wchar_t PlayerName1[12]; // Unicode / Max - 11 Chars + EOS (12 total)
unsigned long Unknown5; // 02 00 FF FF
unsigned long PlayerIndex;
};
[By the way: short is 2 bytes, long is 4 bytes, wchar_t is 2 bytes [thus playerName is 12 * 2 bytes], unsigned denotes value >= 0].
I'm now going to define the address of the first static player structure, which is indeed the host.
(ALL_CAPS_VARIABLES are constants/definitions for my use)
Code: Select all
FIRST_STATIC_PLAYER_ADDRESS = 0x4BD7AFD0
I'm also going to define the size of a static player structure.
Now assuming playerIndex exists, I can find the static player structure address of any player I want. If playerIndex is 0, it corresponds to the first player [the host], if playerIndex is 1 it corresponds to the second player, and etc up until and including 15.
Code: Select all
staticPlayerAddress = FIRST_STATIC_PLAYER_ADDRESS + STATIC_PLAYER_SIZE * playerIndex
We will want the object id address in the static player structure because it'll help us determine the dynamic structure's address (more on that later).
Code: Select all
#this is the offset from the top of the static player structure to the object ID
STATIC_PLAYER_OBJECT_ID_OFFSET = 0x32
playerObjectIDAddress = staticPlayerAddress + STATIC_PLAYER_OBJECT_ID_OFFSET
Then get the object ID of the player:
Code: Select all
playerObjectID = readUInt16(playerObjectIDAddress)
Now, in Halo, there exists an object table structure which looks like this:
Code: Select all
struct Object_Table_Array
{
unsigned short ObjectID; // Matches up to Object ID in static player table ( for players )
unsigned short Unknown0;
unsigned short Unknown1;
unsigned short Size; // Structure size
unsigned long Offset; // Pointer to the object data structure
};
Each object table structure corresponds to a certain halo object; the kind of halo object we are interested in are the dynamic player structures. If we can figure out where the object table structure is, we can figure out where the actual object is. In Halo, there's a consecutive array of these object table structures in memory.
I've just so happened to figure out the first object table structure address in the demo, and of course, the size of every structure.
Code: Select all
FIRST_TABLE_OBJECT_ADDRESS = 0x4BB206EC
OBJECT_TABLE_SIZE = 12
The offset field in the object table structure is the address to the actual halo structure (dynamic player structure in our case). We need to figure out the offset to this field from the object table structure (fairly easy to do; size of short [2] * 4 shorts = 8 bytes)
Code: Select all
OFFSET_TO_HALO_OBJECT_POINTER = 0x8
Before we can get the address to the object table that corresponds to the dynamic player structure, we need to make sure the object ID we calculated earlier is valid. In this particular case, this means things like making sure the player is in the game and the player is still alive.
Code: Select all
INVALID_OBJECT_ID = 0xFFFF #(assuming unsigned, otherwise -1 signed)
#Sanity check
if playerObjectID != 0 and playerObjectID != INVALID_OBJECT_ID:
Then we calculate the address to the halo object pointer [pointer aka variable that holds a memory address] inside the object table structure we want by using the object ID.
Code: Select all
dynamicPlayerPointer = (FIRST_TABLE_OBJECT_ADDRESS + playerObjectID * OBJECT_TABLE_SIZE) + OFFSET_TO_HALO_OBJECT_POINTER
Yup, that's the point of the object ID: accessing the object table array so that we can then access the actual object.
Then we can get the dynamic player address:
Code: Select all
dynamicPlayerAddress = readUInt32(dynamicPlayerPointer)
The dynamic player structure looks something like this:
Code: Select all
struct Dynamic_Player
{
unsigned short MetaIndex;
unsigned short MetaID; // matches against the map's meta table
unsigned char Unknown0[88];
float x; // world coordinate
float y; // world coordinate
float z; // world coordinate
float x2; //movement vector
float y2; //movement vector
float z2; //movement vector
float LegsPitch;
float LegsYaw;
float LegsRoll;
float ScaleX;
float ScaleY;
float ScaleZ;
unsigned char Unknown1[84];
float Health;
float Shield;
unsigned char Unknown2[48];
unsigned short WeaponIndex;
unsigned short WeaponID;
unsigned short VehicleIndex;
unsigned short VehicleID;
unsigned char Unknown3[228];
unsigned long IsInvisible; // normal = 0x41 invis = 0x51 (bitfield?)
unsigned char IsCrouching; // crouch = 1, jump = 2
};
Now we can determine (by hand under assumption again) the offset to the x, y, and z player locations from the dynamic player structure.
Code: Select all
OFFSET_TO_PLAYER_X_COORDINATE = 0x5C
OFFSET_TO_PLAYER_Y_COORDINATE = OFFSET_TO_PLAYER_X_COORDINATE + 0x4
OFFSET_TO_PLAYER_Z_COORDINATE = OFFSET_TO_PLAYER_X_COORDINATE + 0x4 * 2
The x, y, z variables are all floats (4 bytes long). You can grab them like this.
Code: Select all
playerX = readFloat(dynamicPlayerAddress + OFFSET_TO_PLAYER_X_COORDINATE)
playerY = readFloat(dynamicPlayerAddress + OFFSET_TO_PLAYER_Y_COORDINATE)
playerZ = readFloat(dynamicPlayerAddress + OFFSET_TO_PLAYER_Z_COORDINATE)
[Notice that "dynamicPlayerAddress + OFFSET_TO_PLAYER_X_COORDINATE" is equivalent to saying playerXAddress; I just didn't feel like making and storing such variables].
I suppose rotation here might be legsPitch/Yaw/and Roll in the dynamic player structure. The offsets from the dynamic player structure are simply:
Code: Select all
OFFSET_TO_LEGS_PITCH = OFFSET_TO_PLAYER_Z_COORDINATE + 0x4 * 4
OFFSET_TO_LEGS_YAW = OFFSET_TO_LEGS_PITCH + 0x4
OFFSET_TO_LEGS_ROLL = OFFSET_TO_LEGS_PITCH + 0x4 * 2
Grabbing them would be just the same:
Code: Select all
playerLegsPitch = readFloat(dynamicPlayerAddress + OFFSET_TO_LEGS_PITCH)
playerLegsYaw = readFloat(dynamicPlayerAddress + OFFSET_TO_YAW_PITCH)
playerLegsRoll = readFloat(dynamicPlayerAddress + OFFSET_TO_LEGS_ROLL)
[edit]: Fixed & added some bit of information about obtaining dynamicPlayerAddress.