Preface

The goal of this guide is to provide information on how to find offsets for MySEQ Server version 1.20, and to document the myseqserver.ini file. This guide assumes that the only prior knowledge the reader has is a functional understanding of the Windows operating system and EverQuest. However, knowledge and experience with concepts such as hexadecimal numbers, endianness, pointers, data structures, and linked-lists will significantly aid in understanding this guide.

Background

The information in this section is not necessary if you find the offsets the easy way. See below. Some readers may want to search for more information on specific topics before finding offsets. Wikipedia is a good resource for finding more information.

MySEQ works by reading EQ's memory to find the information that it displays. A specific location in memory is referred to as a memory address. A memory address is generally referenced as a hexadecimal number. A hexadecimal number simply put, is a random series of the digits 0-9 and A-F. They represent a number just like the number system you are used to. They are just more convenient for computers. Hexadecimal numbers are usually prefixed with a 0x to distinguish them from other number systems. Memory addresses are referenced by a series of eight hexadecimal characters. (Note: This does not hold true for 64bit computers. However, EQ is a 32bit program so memory addresses will always be eight hexadecimal digits regardless of whether or not you have a 64bit computer.) When writing a memory address sometimes leading zeros will not be written. The hexadecimal numbers 0x0000123f and 0x123f are equivalent. You may want to seek more information on how to the hexadecimal number system works.

A memory address specifies the location of a byte of memory. Bytes can be represented as two hexadecimal digits. All computer memory is stored as bytes. Even the characters on your screen are stored in memory as bytes. The character A is stored as a byte with the hexadecimal representation being 0x41. Some things take more than one byte to store. The memory address of the location where data is stored in memory always points to the first byte. For example the number 21568 would be stored as two bytes the hexadecimal value being 0x5440. If the memory address of the number is 0x1000, then the byte at the memory address 0x1000 would be 0x54 and the byte at the memory address 0x1001 would be 0x40.

When a CPU reads and writes memory it reverses the bytes. (Note: This is not true for all processors, but it is true for all processors that run EQ.) The order that bytes are written in is called endianness. Little endian means that the bytes are reversed. So if I write the 4 byte hexadecimal number 0x12345678 into memory, the CPU actually writes 0x78563412. Endianness is not normally an issue, because although a CPU writes the bytes backwards it also reads them backwards. Endianness becomes important though when looking at raw memory.

The offsets tell MySEQ where in EQ's memory it should look to find the information it is interested in. The offsets are generally classified into two categories, primary and secondary offsets. Primary offsets are absolute memory addresses. This means that they never change. Secondary offsets are relative memory addresses. This means that they specify a distance or offset from a memory address. Individual offsets may or may not change after a patch. It is however relatively uncommon for secondary offsets to change.

All primary offsets except for ZoneAddr are pointers. Located at the memory address of a pointer is another memory address. Thus a pointer "points" to another memory address. As an example, the offset TargetAddr points to your current target. More specifically, it contains the memory address where it can find information about your target. Pointers are always 4 bytes or 8 hexadecimal digits long, because they contain a memory address.

EQ creates blocks of memory where it stores all the information it needs about NPCs, players, ground drops, etc. These blocks are called structures. A structure is a contiguous block of bytes preset bytes in the block specify specific values. MySEQ is capable of reading two types of structures. It reads ground item structures, which includes items on the ground and static tradeskill containers. It also reads spawn structures, which includes NPCs, players, traps, pets, camp fires, etc. As an example a spawn structure contains the name, level, race, class, etc. of the spawn. Pointers to a structure always point to the very beginning of the structure. The memory address to the beginning of a structure is referred to as a base address.

Secondary offsets come in two types ground items and spawns. If pointers always point to the beginning of a structure, secondary offsets are necessary to locate specific information in a structure. For example, the NameOffset specifies where it can find the name of a spawn relative from the beginning of the spawn structure. More specifically, a secondary offset specifies the number that must be added to the pointer to the structure to get the memory address of the specific information you are looking for.

Because structures are located at arbitrary memory locations, they are linked in a long chain to make it possible for EQ to keep track of them. EQ then only has to know the memory address of one structure and it can find any structure it wants by following the chain. This is called a linked list. The spawn and ground item structures are doubly linked. That means that each structure contains a pointer to two different structures, the structure that preceded it and the structure that comes after it. If no structure precedes or follows a structure in a linked list the respective pointer points to the memory address 0x00000000. This occurs at either end of a linked list.

All MySEQ then has to do is read the pointer that EQ keeps that points to one of the structures. Then MySEQ can follow the chain of structures reading the information it is interested out of each one, until it reaches the end of the list. This location of this pointer is actually the primary offset named SpawnHeaderAddr.

Example:
Code:
The primary offset points to where EQ stores a spawn structure.
SpawnHeaderAddr=0x950000

The secondary offsets points to where the information can be found from the beginning of the spawn structure.
NameOffset=0xa4
LevelOffset=0x2d8
NextOffset=0x4
PrevOffset=0x8

At 0x950000 it points to a spawn structure at 0xa80000.
0x950000: 0xa80000

The beginning of a spawn structure.
0x00a80000:
The pointer to the next spawn structure.
0x00a80004: 0x00a90000
The pointer to the previous spawn structure. It is zero so there is no previous.
0x00a80008: 0x00000000
Name of the spawn.
0x00a800a4: Goner00
Level of the spawn.
0x00a802d8: 60

0x00a90000:
0x00a90004: 0x00000000
0x00a90008: 0x00a80000
0x00a900a4: Imacoolmage
0x00a902d8: 80

Offsets Specification

Offsets are always stored in a text file named myseqserver.ini located in the same folder as MySEQ server. The offsets are separated into five sections. Each section starts with its name enclosed in brackets [SectionName]. Each section contains keys. Each key has a value. Keys are specified by their name followed by an equals sign and their value Key=Value. Every key and section must be on their own line. If the value of a key is a number, a 0x must be prefixed if the number is hexadecimal. Decimal numbers are also legal. All keys that contain offsets are memory addresses. Primary offsets are absolute addresses, and secondary offsets are relative addresses.

Section [File Info]

PatchDate Date of the EQ patch for which the offsets correspond to in mm/dd/yyyy format.


Section [Port]

port TCP port number that the server listens on. Default is 5555.


Section [Memory Offsets] (Also known as primary offsets)

ZoneAddr (? bytes) Address of the null-terminated string that contains the short zone name of the zone you are currently in. The short zone name is the same as the file name for the corresponding EQ map file minus the file extension. Is empty if between zones. Ex: guildlobby, poknowledge

CharInfo (4 bytes) Address of the pointer to the spawn structure for the character that is currently logged in.

SpawnHeaderAddr (4 bytes) Address of the pointer to the first spawn structure in the list. This is usually set to the same value as CharInfo because the currently active character is usually the first one in the list. The server can handle cases where SpawnHeaderAddr does not point to the first spawn structure.

TargetAddr (4 bytes) Address to the pointer to the spawn structure for the spawn currently targeted. Set to zero if no spawn is targeted.

ItemsAddr (4 bytes) Address of the pointer to the first item structure in the list. The server cannot handle cases where ItemsAddr does not point to the first item structure.


Section [SpawnInfo Offsets] (Also known as secondary offsets)

NextOffset (4 bytes) Pointer to the next item in the list.

PrevOffset (4 bytes) Pointer to the previous item in the list.

NameOffset (? Bytes) Null-terminated string that specifies the spawn name. All spaces are replaced with underscores. All spawns that are not players have two decimal digits at the end.

LastnameOffset (? Bytes) Null-terminated string that specifies that spawn last name. All spaces are replaced with underscores.

XOffset (4 bytes) A floating point number that represents the spawn's current position on the X axis.

YOffset (4 bytes) A floating point number that represents the spawn's current position on the Y axis.

ZOffset (4 bytes) A floating point number that represents the spawn's current position on the Z axis.

SpeedOffset (4 bytes) A floating point number that represents the spawn's current speed in the direction of movement in grid units per second.

HeadingOffset (4 bytes) A floating point number that represents the spawn's current direction. The number represents an angle in degrees, zero being north. The angle must be less than 360 degrees.

TypeOffset (1 byte) A number that represents the spawn's type. Possible values can be found in SpawnTypes.txt with the MySEQ client. The numerical representation of the values are the line number in the file. The first line being zero.

LevelOffset (1 byte) A number that represents the spawn's level.

RaceOffset (2 byte) A number that represents the spawn's race. Possible values can be found in Races.txt with the MySEQ client. The numerical representation of the values are the line number in the file. The first line being zero.

ClassOffset (1 byte) A number that represents the spawn's class. Possible values can be found in Races.txt with the MySEQ client. The numerical representation of the values are the line number in the file. The first line being zero.

HideOffset (1 byte) A number that represents the spawn's visible state. Possible values can be found in VisTypes.txt with the MySEQ client. The numerical representation of the values are the line number in the file. The first line being zero.

SpawnIDOffset (4 bytes) A number representing a unique identifier for a spawn. Although the server does read the offset from the myseqserver.ini file, it replaces the spawn ID with the base address of the spawn structure when it sends the spawn information to the client.

Section [GroundItem Offsets] (Also known as secondary offsets)

PrevOffset (4 byte) Pointer to the previous item in the list.

NextOffset (4 bytes) Pointer to the next item in the list.

XOffset (4 bytes) A floating point number that represents the item's current position on the X axis.

YOffset (4 bytes) A floating point number that represents the item's current position on the Y axis.

ZOffset (4 bytes) A floating point number that represents the item's current position on the Z axis.

IdOffset (4 bytes) A number representing a unique identifier for an item.

DropIdOffset (4 bytes) Unknown meaning, not currently used in the MySEQ client.

NameOffset (? Bytes) A null-terminated string representing the model that is displayed for an item. Possible values can be found in GroundItems.ini with the MySEQ client.


Finding the Zone Offset

The ZoneAddr offset is the easiest to find, because it is not dependant on any other offsets. Log into a character on EQ. Run MySEQ server with the debug parameter. An easy way to do this is to create a shortcut to myseqserver.exe. Edit the shortcut target and add on debug at the end. Make sure that EQ is running before you run MySEQ server. Once MySEQ server is running in debug mode type fz followed by a space and the short zone name of the zone you are currently in. The short zone name is the same thing as the file name of the map file for the zone, minus the ".txt". Ex: "fz guildlobby", "fz poknowledge". Hit enter. Your results will say "Pointer match found at 0x....". It is normal to get two results. Either should work fine. If you have more than two results, it may mean that something has changed in EQ.


Primary Offsets: The Easy Way

This method will work if the PrevOffset, NextOffset, and NameOffset have not changed. To know if those offsets have changed you simply try this method and if you don't get any results, then they have changed. Log into a character on EQ. Run MySEQ server with the debug parameter.

Finding the SpawnHeaderAddr offset is very similar to finding the ZoneAddr. Type fs followed by your name. Make sure you capitalize the first letter. Ex: "fs Healzalot". Again, two results are okay.

CharInfo is the same as the SpawnHeaderAddr offset.

For the TargetAddr offset you target a player. Type ft followed by the name of your target. Do not use non-players, unless you know how to change the name into the format stored in memory. You can target yourself, but it will have multiple results. Ex: "ft Handulofen". There is only one valid offset for this one. Test each one to find the correct offset.

For the ItemsAddr offset you type sg. Multiple results are normal for this offset as well, but there is only one valid offset. After it prints the offset it also prints the name of the item. A valid item will have a name similar to "IT0000_ACTORDEF". Again, test each possible offset until you find the correct one.

You now have all the primary offsets. Run MySEQ and make sure that all the information is correct. If the wrong information is being displayed, you may have to update some of the secondary offsets.


Finding Secondary Offsets

If you found the primary offsets the easy way, then you know that the PrevOffset, NextOffset, and NameOffsets are correct. Run MySEQ and determine which secondary offsets need to be updated. For example if every spawn has a level of zero, then the LevelOffset needs to be updated. The basic procedure for finding secondary offsets is to scan the structures of known spawns and items for known values. You record all the relative addresses where the known value exists. You continue to scan structures until all the structures you have scanned only share one relative address. Because the structure for ground items is so small and you rarely know values, it is usually better to view the ground item structures with a hex editor capable of reading memory addresses and doing this process manually. You can also use the memory viewer in Cheat Engine to do this. To scan the memory you need a memory scanner that allows you to specify a start and end memory address to scan. The memory scanner I use is Cheat Engine you can find it at http://www.cheatengine.org/downloads.php.

First you have to find the base address of a structure. For spawns you can get a pointer to the base address of a spawn structure by targeting a spawn and reading the TargetAddr offset. The base address of a spawn structure can also be found in the client in the SpawnID field. Note that the SpawnID is written as a decimal number. In cheat engine you can manually add the TargetAddr offset so it will always display its value. For ground items you use the ItemsAddr offset to find a ground item and follow the previous and next pointer to get additional ground items.

Once you have the base address you search for the known value starting from the base address and ending 0x2000 bytes from the base address. Make sure you set the value length or value type in the memory scanner. More information on the length and representation of secondary offsets can be found in the Offsets Specification section. For example if you found the base address of the spawn structure for your character to be 0xa83400. You are looking for the level offset and you know that you are level 70. You scan from 0xa83400 to 0xa85400 you search for a one byte value with the value 70. The memory scanner will give you the absolute memory addresses of the matching values. You subtract the absolute address from the base address to get the relative address.

You continue scanning spawn structures until all your scans only share one relative address. Congratulations you found a secondary offset.


Offsets: The Hard Way

If the PrevOffset, NextOffset, or NameOffsets have changed the above methods will not work. The goal is to find these three secondary offsets so that we can use the above methods. The basic method for doing this is to first find a structure. Once you have found a structure you look at the memory in it to find pointers. You follow the pointers and see if they bring you to another structure. Once you find a pointer that brings you to another structure you verify another pointer exists in the same position in the new structure.

To find a structure you scan EQ's memory using the name of a known spawn or item. There are a few things to keep in mind here. If you scan for the name of the character you are currently logged into you will get many results. Keep in mind that memory is reused, and when memory is deleted it does not clear the contents of the memory. When a structure is created all the pointers and the information inside it is valid. When the structure is no longer needed EQ simply changes the previous and next pointers of the structures that are linked to it. Since the structure is no longer needed EQ is free to write over the memory for the old structure at any time. Even if the EQ does not write over the memory of a deleted structure, the previous and next pointers are not guaranteed to be valid. They could point to structures that were also deleted, and may have been overwritten. It is best to restart EQ before you start looking for structures and not to zone while looking. You should also look for NPCs with text under their name in parenthesis. Players may zone out at any time. When you search for ground item names it may be best to search for an item that you know only exists once in the zone.

No matter which name you search for you should find multiple results. For ground items you can skip to the next step to eliminate the possibilities. For spawns you have to look at the memory near the results. Valid spawn structure should contain the last name in the area near the name. For NPCs the last name is the text written under their name in parenthesis.

Once you have found a structure you have to look in the area around the name for the previous and next pointers. For ground items this is fairly easy because the structure is very small. There are a few things you should keep in mind for this step as well. The previous and next pointers are almost always next to each other. The pointers themselves as well as the value of the pointers should always be aligned to 32bits. This means that their absolute address ends with a 0, 4, 8, or c. Pointers usually precede the name. Pointers usually either have two leading zeros or start with 10 or 20. Don’t forget endianness!

Once you have found something that looks like a pointer you can view the memory near its address. You should see a name in the memory near it. If there is no name then it is probably not the previous or next pointer. If it is a spawn structure it should also have a last name if the spawn has one. If you find a name in the new structure, you move the same number of bytes from this name to the pointer that you did in the first structure. If this pointer also points to a structure with a name in it, then you are done!

To compute the exact offsets you subtract the absolute address of the name from the base address of the structure to get the NameOffset. Remember previous and next pointers always point to the base address of a structure. You do the same thing for the previous and next pointers to find PrevOffset and NextOffset respectively.

It can be difficult to know which pointer is pointing to the previous structure and which pointer is pointing to the next structure. MySEQ does not care if the PrevOffset actually points to the next pointer or the previous pointer. However, for performance reasons the PrevOffset should be the pointer that is set to zero for the first structure in a list. Congratulations you can now find the primary offsets then fix any other secondary offsets. Once you have them you can fix your previous and next offsets.