I put the whole question in 2 images. From research, it seems I need to use Ctrl+R, but I don't think that's what I need since I couldn't lower the number a bit further in order to reach 0.

I think the problem is that I'm not creating the structs properly.

I'd like to add a few guesses the number went down to 16072 because the array of PlayerPointers is 4 bytes per element. So it went down 64288 / 4 = 16072.
I still don't know what that means.

problem 1 asm code

ASM Code:

.text:0040E040 ; =============== S U B R O U T I N E =======================================
.text:0040E040 ; struct_ARENA *__thiscall code(struct_PLAYER *player, const void *buf, unsigned int len, int a4)
.text:0040E040 sub_40E040      proc near               
.text:0040E040 buf             = dword ptr  4
.text:0040E040 len             = dword ptr  8
.text:0040E040 a4              = dword ptr  0Ch
.text:0040E040                 push    ebx
.text:0040E041                 push    esi
.text:0040E042                 mov     esi, ecx
.text:0040E044                 mov     eax, [esi+1Ch]
.text:0040E047                 test    eax, eax
.text:0040E049                 jz      short loc_40E093
.text:0040E04B                 mov     ecx, [eax+0FF0Ch]
.text:0040E051                 xor     ebx, ebx
.text:0040E053                 test    ecx, ecx
.text:0040E055                 jle     short loc_40E093
.text:0040E057                 push    edi
.text:0040E058                 push    ebp
.text:0040E059                 mov     ebp, [esp+10h+a4]
.text:0040E05D                 mov     edi, 0FB20h
.text:0040E062 loc_40E062:                             
.text:0040E062                 mov     eax, [edi+eax]
.text:0040E065                 cmp     eax, esi
.text:0040E067                 jz      short loc_40E082
.text:0040E069                 mov     ecx, [eax+38h]
.text:0040E06C                 test    ecx, ecx
.text:0040E06E                 jnz     short loc_40E082
.text:0040E070                 mov     ecx, [esp+10h+len]
.text:0040E074                 mov     edx, [esp+10h+buf]
.text:0040E078                 push    ebp             ; a4
.text:0040E079                 push    ecx             ; len
.text:0040E07A                 push    edx             ; buf
.text:0040E07B                 mov     ecx, eax        ; this
.text:0040E07D                 call    SendPlayerReliablePacket
.text:0040E082 loc_40E082:                             
.text:0040E082                 mov     eax, [esi+1Ch]
.text:0040E085                 inc     ebx
.text:0040E086                 add     edi, 4
.text:0040E089                 cmp     ebx, [eax+0FF0Ch]
.text:0040E08F                 jl      short loc_40E062
.text:0040E091                 pop     ebp
.text:0040E092                 pop     edi
.text:0040E093 loc_40E093:                            
.text:0040E093                 pop     esi
.text:0040E094                 pop     ebx
.text:0040E095                 retn    0Ch
.text:0040E095 sub_40E040      endp
.text:0040E095 ; ---------------------------------------------------------------------------
.text:0040E098                 align 10h

Here is one that looks better only 1 struct instead of 2 but still same problem

enter image description here

Here is the amount of players who are not watching but playing the game.

int __thiscall TotalPlayingPlayers(struct_ARENA *arena)
  int ArenaPlayerCount; // edx@1
  int result; // eax@1
  struct_PLAYER **eachPlayer; // ecx@2

  ArenaPlayerCount = arena->ArenaPlayerCount;
  result = 0;
  if ( ArenaPlayerCount > 0 )
    eachPlayer = arena->playerPointersForSomething;// How could this be like this? this would only hold 251 4 bytes not enough for all players.
      if ( (*eachPlayer)->Ship != 8 )
      ++eachPlayer;                             // This means it really has to go up by 4 bytes the small 251 array.
    while ( ArenaPlayerCount );
  return result;

here is image of above


1 Answer 1


It seems to me that you're wrong if you assume v7 is an index - v6 is.

The original function was probably something like

int v6=0;
while (v6 < result->ArenaSubStruct.ArenaPlayerCount) {   // <-- what is a if/do while in your disassembly was originally a while
    eachPlayer = result->ArenaSubStruct.PlayerPointers[v6];
    if (eachPlayer != player)                            // <-- v4 and player are identical
        SendPlayerReliablePacket(eachPlayer, buf, len, a4);

To optimize this, the compiler introduced v7 as a pointer to the array element corresponding to the loop variable. This way, the processor just needs to access a pointer (and increment the pointer by the size of the int it points to) instead of a multiplication and add per loop:

int v6=0;
int v7=offsetof(*result, ArenaSubStruct.PlayerPointers);
while (v6 < result->ArenaSubStruct.ArenaPlayerCount) {
    eachPlayer = *(int *)((char *)result+v7)
    if (eachPlayer != player)
        SendPlayerReliablePacket(eachPlayer, buf, len, a4);
    v7+=sizeof(ArenaSubStruct.PlayerPointers[0]);   // which is an it so sizeof returns 4

So your v7 is not an index into the PlayerPointers structure that should be brought down to 0, instead, it's an "index" into the ArenaSubStruct structure, that starts with the offset of PlayerPointers within ArenaSubStruct. You can't get that back nicely in IDA, because there's no nice C representation of what the compiler did - look at the ugly type casts i had to do.

  • makes sense.. also seems if I make the PlayerPointers into a dd then press * it says only 251 possible DWORD's (1004/4) can fit in there.. when I know atleast 1024 or 1025 players are possible? Plus there isn't enough room in the struct for anymore because ArenaPlayerCount starts and that's a real variable.
    – SSpoke
    Apr 17, 2014 at 8:25
  • Does your game support something like watchers, who don't play themselves but can see what the players do? Your Struct would split up nicely if you had 1024 player structures of 62 bytes each at the start (end Address 0xFB20), then 250 4-byte-integers (end Address FF08), then another 4 byte integer variable which is the count of real players, then the 4 byte integer you named ArenaPlayerCount at FF0C. If the variable at FF0C is the Watcher count (with the real player count at FF08?), the above function would fit a "Inform all watchers" pattern nicely. Apr 17, 2014 at 11:33
  • Yes but that's the thing there could be as much watchers as there are players so 1024/1025 possible watchers or players playing at any moment. Any player can become into a watcher by changing their ship. I already found the function which indicates the watchers it's very similar to this one I think it uses the same array I'll post it. in the question
    – SSpoke
    Apr 17, 2014 at 15:34
  • I put my IDA can you let me know the issues.. I remade it mediafire.com/?qnqb00q4yk4kq6v
    – SSpoke
    Apr 18, 2014 at 9:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.