Go Back

Rift - Entity Components

My previous blog basically showed you how I got all the entities from Rift, but it did not show you how to get the needed data from the entities. Thing's like 'what type of entity is it', 'where is it located', etc. In this blog I'll try to explain how I found out how Rift stores this data.

As with my previous blog, I wrote using an open-beta executable. For this part it is a must. The release-executable no longer contains the information that I will be talking about, which will make it a whole lot harder to find out which entity component your dealing with.

When analyzing Rift (when looking at how it handles entity data) you will often see code that looks like this:

v5 = *(_BYTE *)(dword_12055DC + entity + 24);
if ( v5 == -1 )
  v6 = 0;
else
  v6 = *(_DWORD *)(*(_DWORD *)(entity + 88) + 4 * v5);

The dword_12055DC usually varies, but the code is almost always the same. Although you might sometimes see it mixed up in other if-statements (usually it's only the first line of the above block).

Basically every entity in Rift is build up out of several components, the code that is shown gets the entity component address (if the component exists). From what I gather, each component has an id/index. When a component gets added to an entity, it's component index is used to look up the index of the address. Why the component index isn't directly used directly to get the address is a bit of a mystery to me.

The above code however does not get you very far, considering there are likely around 64 possible entity components. To find out what entity component the game is accessing you need an open-beta executable. They removed the string-names (for each component) from the release.

If we look at the cross reference of dword_12055DC, you will notice that there is one line of code that stands out "mov eax, offset dword_12055DC". This line is shared between all entity components. If we go to the function, you will notice that the only thing it does is return the offset. If we cross reference that function, we will notice its used in a v-table.

We're interested in the first function in the v-table, usually (always?) the constructor, to give us a clue on which component it is. The release executable has no info for you there (as said they removed all string references). However the above component had this constructor in the beta:

_UNKNOWN *__cdecl sub_615970()
{
  int v0; // eax@2

  if ( !(dword_1264178 & 1) )
  {
    dword_1264178 |= 1u;
    v0 = sub_5CB980(0);
    sub_A2B6C4((int)&unk_126414C, "ClientEntityComponentNPC", v0);
    atexit(sub_105B3B0);
  }
  return &unk_126414C;
}

Now isn't that lovely, we just got the name of the component. While it doesn't magically give you all the information that you need, it does help you understand what it is used for.

For me, 5 components where of interest:

  • The ClientEntityComponentActor component, it stores health of the entity
  • The ClientEntityComponentPlayer component, it stores the player's name
  • The ClientEntityComponentNPC component, it stores the NPC's name (but only if it is different from it's original name)
  • The ClientEntityComponentMod component, it stores the entities faction
  • The ClientEntityComponentTransform component, it stores the location of the entity

I will not go into detail on all of these components (heck I don't know half of the info that is stored in them), but I will go into two. The Transform component and the Player component.

The Transform component is the easiest of them all. We have to look up the /loc command. Using the same technique used in the previous blog. When looking at the code of SlashLoc, we notice that it uses an entity component (ClientEntityComponentTransform) and right after that it loads a couple of variables from the address.

v3 = *(_BYTE *)(ClientEntityComponentTransform + entity + 24);
if ( v3 == -1 )
  v4 = 0;
else
  v4 = *(_DWORD *)(*(_DWORD *)(entity + 88) + 4 * v3);
v6 = *(_DWORD *)(v4 + 0x3C);
v12 = *(_DWORD *)(v4 + 0x38);
v14 = *(_DWORD *)(v4 + 0x40);

You can probably guess what it loads. As I said, this was the easiest (and I wasn't kidding! :).

The Player component probably stores a lot more then "just the name" but I only needed the name. Unlike the Transform component, the player's name is stored 2 levels deep.

To find the player name we go back to the SlashTarget function from the previous blog, and we go into sub_64A500 again. We look through the function and dive into sub_5E5110 and then dive straight into the only function in there as well. If you look into that function, you will see three components being used. There's a big if-statement, checking if there is a player address or not. We are interested in the first function that gets called when there is a player address (sub_616270).

If you look into that function, the first code line reads as follows (in the o-beta exe) "sub_57B7E0((void *)(*(_DWORD *)(this + 0x2C) + 0xA0), (int)&v3);", and guess what. In the open beta, the pointer at "((playerNameAddress + 0x2C) + 0xA0)" pointed to a unicode string with the player name in it. In the release its 0x2C + 0x180 .

The use of entity components makes it a lot harder to find values that your interested in. I, for example, would love to find out the class of a player. But haven't gotten around to looking at where the game stores it. Health took a while to figure out, I found that using a debugger and simply back-tracing each of the pointer addresses.

For the standings/faction I used "SlashFollow", since you can't follow enemies the game must check the standings in "SlashFollow" (and it does).

I have no code example for this part, but if anyone is interested, I could make an example for it. Leave a comment if you are (or if you have questions).

One small warning, there's some extensive error checking inside Rift, crashing the client (or pausing the debugger too long when performing certain actions) can get you banned!  Be careful!

Posted by: Da_Teach on Monday, March 7, 2011  •  Pointers Rift IDA Pro

  • Facebook
  • Twitter
  • DZone It!
  • Digg It!
  • StumbleUpon
  • Technorati
  • Del.icio.us
  • NewsVine
  • Reddit
  • Blinklist
  • Add diigo bookmark
Post a comment!
  1. Formatting options