Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Agents #25

Open
Nostrademous opened this issue Dec 19, 2018 · 40 comments
Open

Multiple Agents #25

Nostrademous opened this issue Dec 19, 2018 · 40 comments

Comments

@Nostrademous
Copy link
Collaborator

Since we are moving to multi-agent design I wanted to raise the question of how many agents do we actually want.

At start there are two possibilities:

  1. One Agent Per Hero (5 agents per Team)
  2. One Master Agent that controls 5 heroes

*3) One Agent Per Hero and Per Controllable Unit (meaning summons (Nerconomicon, Warlock Ultimate, Beastmaster Hawk & Boar, etc.), illusions (Manta, Illusion Rune, Wall of Replica, Disruption, etc.), clones (Meepo), doubles (Arc Warden Ultimate) or dominated (i.e., Helm of Dominator, Enchantress, Chen, etc.) units) - typically these are controlled by the same agent that is controlling the owning Hero that caused the summon/domination to occur, but doesn't have to be.

Each approach has its pros and cons in terms of flexibility (co-play with humans, etc.), agent action synchronization (via shared world state model versus independent world models), training time, and so forth. OpenAI went with #1 above, but we do not necessarily have to, although I think I would prefer #1 above as well.

Next, there are a few other things that could be their own agents:
a) Courier - there is one courier per team - it can be controlled by any Hero Agent and even in real games it often gets abused by numerous players at once. We could make it its own agent.
b) Glyph Usage - anyone on the team can use the Glyph (when available)
c) Minimap Scan - anyone on the team can use the Minimap Scan function

*d) One Team Agent to control a), b) and c) as a single entity

Just wanted to throw this out there to think about and post your thoughts.

@TimZaman
Copy link
Owner

TimZaman commented Dec 19, 2018 via email

@Nostrademous
Copy link
Collaborator Author

By the way, I see that you are using "auto-generated files" as a means to communicate between the bots and the agent. This assumes they always exist on the same hardware, basically disallowing the possibility of dotaservice running on one physical host while the agent code runs on a different one (well, short of doing network file transfers between the two).

I previously implemented the comms method of using CreateHTTPRequest() API (and I believe there is also a CreateRemoteHTTPRequest() API - could be wrong - Valve kept flip-flopping between allowing this and not):
https://github.com/Nostrademous/Dota2-WebAI/blob/master/webserver_out.lua#L443-L467

While not necessarily "reliable", it is WAY faster than using files as a comms method. Currently I'm seeing the Think() function take 18-20ms for Nevermore, whereas I believe the method I had above was about 10x less time. I believe this has to do with "loadfile" being rather slow, but I could be wrong.

@TimZaman
Copy link
Owner

TimZaman commented Dec 19, 2018 via email

@Nostrademous
Copy link
Collaborator Author

I'm fine with file passing providing it's "fast enough" which I believe it is.

Back to the initial question though - as we slowly transition to 5 agents and self-play (10 agents) - what about courier/glyph/scan functions - are they part of each agent or their own entities?

@TimZaman
Copy link
Owner

TimZaman commented Dec 19, 2018 via email

@Nostrademous
Copy link
Collaborator Author

which library/executable did the "Init" reside in?

I guess I'm asking if you know if the functions I am to find the signatures for exist in the main dota2 binary or a specific library that gets loaded for handling bots

@TimZaman
Copy link
Owner

TimZaman commented Dec 19, 2018 via email

@Nostrademous
Copy link
Collaborator Author

Observe(size_t teamID, void *, void *)

First arg is team ID. 2 for Radiant, 3 for Dire.

Busy with kids right now but I believe 2nd will be pointer to protobuf.

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018 via email

@Nostrademous
Copy link
Collaborator Author

* thread #1, name = 'MainThrd', queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000090f2f9e0 botcpp_radiant.so`Observe
    frame #1: 0x00000000892c53e1 libserver.dylib`___lldb_unnamed_symbol90409$$libserver.dylib + 769
    frame #2: 0x00000000892bc2cd libserver.dylib`___lldb_unnamed_symbol90399$$libserver.dylib + 925
    frame #3: 0x000000008923ab65 libserver.dylib`___lldb_unnamed_symbol89338$$libserver.dylib + 629
    frame #4: 0x0000000088829641 libserver.dylib`___lldb_unnamed_symbol30869$$libserver.dylib + 129
    frame #5: 0x0000000088b5c8bb libserver.dylib`___lldb_unnamed_symbol46417$$libserver.dylib + 155
    frame #6: 0x0000000088b385c6 libserver.dylib`___lldb_unnamed_symbol45980$$libserver.dylib + 1510
    frame #7: 0x00000000064b97d7 libengine2.dylib`___lldb_unnamed_symbol7478$$libengine2.dylib + 503
    frame #8: 0x000000000639c3fe libengine2.dylib`___lldb_unnamed_symbol2598$$libengine2.dylib + 174
    frame #9: 0x0000000006398b5e libengine2.dylib`___lldb_unnamed_symbol2557$$libengine2.dylib + 126
    frame #10: 0x00000000063950a7 libengine2.dylib`___lldb_unnamed_symbol2521$$libengine2.dylib + 2855
    frame #11: 0x0000000006387c8b libengine2.dylib`___lldb_unnamed_symbol2351$$libengine2.dylib + 1339
    frame #12: 0x0000000006387712 libengine2.dylib`___lldb_unnamed_symbol2350$$libengine2.dylib + 18
    frame #13: 0x000000000637b150 libengine2.dylib`___lldb_unnamed_symbol2189$$libengine2.dylib + 384
    frame #14: 0x000000000637b880 libengine2.dylib`___lldb_unnamed_symbol2190$$libengine2.dylib + 1040
    frame #15: 0x000000000637bbaa libengine2.dylib`Source2Main + 298
    frame #16: 0x000000000630cd65 dota2`___lldb_unnamed_symbol6$$dota2 + 197
    frame #17: 0x00007fff69c6908d libdyld.dylib`start + 1

That's the callstack to get to our Observe call

@TimZaman
Copy link
Owner

The only open q is: what should Act return?

@Nostrademous
Copy link
Collaborator Author

I agree, makes the most sense, but wouldn't it have to be wrapped in a CMsgBotWorldState anyways?

@TimZaman
Copy link
Owner

How? What do you mean?

@Nostrademous
Copy link
Collaborator Author

Well, isn't the Msg Actions protobuf embedded inside the CMsgBotWorldState?

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018 via email

@Nostrademous
Copy link
Collaborator Author

Okay, at least reading the Observe() is done.

Example Code:

extern "C" void Observe(int teamID, const CMsgBotWorldState &ws) {
    // The intention of this script is most probably to setup a connection with the
    // worldstate sockets. Kinda weird though, because the dota game would be the server
    // and then this script would be the client of that..
    // Observe is called every tick that corresponds to the worldstate server's ticks,
    // Exactly before the Act() is called.
    cout << "Observe::cout" << endl;
    cout << "TeamID: " << ws.team_id() << endl;
    cout << "DotaTime: " << ws.dota_time() << endl;
    cout << "GameState: " << ws.game_state() << endl;

    for (CMsgBotWorldState_Player player : ws.players() ) { 
        cout << "\tPlayerID: " << player.player_id() << endl;
        cout << "\tHeroID: " << player.hero_id() << endl;
    }   
}

Example Output:

Observe::cout
TeamID: 2
DotaTime: -77.2335
GameState: 4
	PlayerID: 0
	HeroID: 11
	PlayerID: 1
	HeroID: 35
	PlayerID: 2
	HeroID: 35
	PlayerID: 3
	HeroID: 35
	PlayerID: 4
	HeroID: 35
	PlayerID: 5
	HeroID: 35
	PlayerID: 6
	HeroID: 35
	PlayerID: 7
	HeroID: 35
	PlayerID: 8
	HeroID: 35
	PlayerID: 9
	HeroID: 35

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018 via email

@Nostrademous
Copy link
Collaborator Author

Well, we could do a guessing game, but how will we know when we are right?

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018 via email

@Nostrademous
Copy link
Collaborator Author

Well I agree... so easy to test.

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018

So it's (probably)

const CMsgBotWorldState::Actions& Act(int team_id)

But the action is: what are the strictly required values? Or possibly, we might need to return something in Init (or Observe) that toggles some functionality. And still: why is it that we need to keep the worldstate sockets open?

@Nostrademous
Copy link
Collaborator Author

So I assume we need to open the socket in Init() just to trigger pumping the world state through the ports.

@Nostrademous
Copy link
Collaborator Author

could it not be:

extern "C" void Act(int team_id, CMsgBotWorldState_Actions &msg)

I'm thinking that way we don't have to allocate the protobuf and keep track of the memory. Perhaps an INOUT variable.

@Nostrademous
Copy link
Collaborator Author

Tried a bunch of stuff, can't say i was successful on Act() yet.

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018 via email

@Nostrademous
Copy link
Collaborator Author

Will check back tomorrow and work some more on it. 1am here and I have to get up at 6am. Calling it a night for now.

@Nostrademous
Copy link
Collaborator Author

I'm thinking there is a 2nd arg to Act() (only valid after game starts, it's NULL during hero selection. I believe it might be the ArenaAllocator().

Currently this compiles and doesn't crash but still doesn't move.

CMsgBotWorldState_Actions * actions_pb;
CMsgBotWorldState_Action_MoveToLocation * mtl_pb;
CMsgBotWorldState_Vector * loc_pb;

// Returning std::shared_ptr<CMsgBotWorldState::Actions> crashes upon return.
// Returning CMsgBotWorldState::Actions craches.
// void, void *, char* is fine, even if its contents are totally bogus.
extern "C" const CMsgBotWorldState::Actions * Act(int team_id) {
    // Act seems to be called practically _exactly_ after Observe is called.
    // Since it is called once per team, all team-decisions need to be made here. That means
    // that we need to communicate all actions. Probably that means we need to return the actions
    // protobuf somehow. I think returning the protobuffer itself, from this function makes
    // the most sense.
    // This call is fully blocking the entire game, so possible they are indeed waiting for a 
    // synchronous return.
    auto timenow =  chrono::system_clock::to_time_t(chrono::system_clock::now()); 
    cout << "Act::cout @" << ctime(&timenow) << endl;
    cout << "TeamID: " << team_id << endl;

    mtl_pb = new CMsgBotWorldState_Action_MoveToLocation;

    loc_pb = new CMsgBotWorldState_Vector;
    loc_pb->set_x(0.0);
    loc_pb->set_y(0.0);
    loc_pb->set_z(0.0);
    cout << "loc set - addr: " << loc_pb << endl;

    mtl_pb->add_units(test_id);
    mtl_pb->set_allocated_location(loc_pb);

    actions_pb = new CMsgBotWorldState_Actions;
    cout << "new actions_pb created" << endl;
    CMsgBotWorldState_Action * action_pb = actions_pb->add_actions();
    cout << "action_pb referenced" << endl;
    action_pb->set_actiontype(CMsgBotWorldState_Action_Type_DOTA_UNIT_ORDER_MOVE_TO_POSITION);
    action_pb->set_player(4);
    action_pb->set_allocated_movetolocation(mtl_pb);

    std::string s;  
    if (google::protobuf::TextFormat::PrintToString(*actions_pb, &s)) {
        std::cout << "Your message:\n" << s;
    } else {
        std::cerr << "Message not valid (partial content: " << actions_pb->ShortDebugString() << ")\n";
    }   
    
    cout << "Gonna return from act..\n";
    return actions_pb;
}

BTW, as expected, the first arg of Init() is int teamID

@Nostrademous
Copy link
Collaborator Author

Notes for self:

* thread #1, name = 'MainThrd', queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x0000000090a539e0 botcpp_radiant.so`Act
    frame #1: 0x00000000893523f5 libserver.dylib`___lldb_unnamed_symbol90409$$libserver.dylib + 789
    frame #2: 0x00000000893492cd libserver.dylib`___lldb_unnamed_symbol90399$$libserver.dylib + 925
    frame #3: 0x00000000892c7b65 libserver.dylib`___lldb_unnamed_symbol89338$$libserver.dylib + 629
    frame #4: 0x00000000888b6651 libserver.dylib`___lldb_unnamed_symbol30869$$libserver.dylib + 129
    frame #5: 0x0000000088be98cb libserver.dylib`___lldb_unnamed_symbol46417$$libserver.dylib + 155
    frame #6: 0x0000000088bc55d6 libserver.dylib`___lldb_unnamed_symbol45980$$libserver.dylib + 1510
    frame #7: 0x000000000de567d7 libengine2.dylib`___lldb_unnamed_symbol7478$$libengine2.dylib + 503
    frame #8: 0x000000000dd393fe libengine2.dylib`___lldb_unnamed_symbol2598$$libengine2.dylib + 174
    frame #9: 0x000000000dd35b5e libengine2.dylib`___lldb_unnamed_symbol2557$$libengine2.dylib + 126
    frame #10: 0x000000000dd320a7 libengine2.dylib`___lldb_unnamed_symbol2521$$libengine2.dylib + 2855
    frame #11: 0x000000000dd24c8b libengine2.dylib`___lldb_unnamed_symbol2351$$libengine2.dylib + 1339
    frame #12: 0x000000000dd24712 libengine2.dylib`___lldb_unnamed_symbol2350$$libengine2.dylib + 18
    frame #13: 0x000000000dd18150 libengine2.dylib`___lldb_unnamed_symbol2189$$libengine2.dylib + 384
    frame #14: 0x000000000dd18880 libengine2.dylib`___lldb_unnamed_symbol2190$$libengine2.dylib + 1040
    frame #15: 0x000000000dd18baa libengine2.dylib`Source2Main + 298
    frame #16: 0x000000000dca9d65 dota2`___lldb_unnamed_symbol6$$dota2 + 197
    frame #17: 0x00007fff69c6908d libdyld.dylib`start + 1

@TimZaman
Copy link
Owner

TimZaman commented Dec 20, 2018

It's also very much possible the 2nd argument is actually a pointer to an already created [empty] Actions protobuf...

@Nostrademous
Copy link
Collaborator Author

Nostrademous commented Dec 20, 2018

Function that calls our botcpp_*.so

0x8931f3f3 is where Act() is called

(lldb) disassemble --frame -mixed
libserver.dylib`___lldb_unnamed_symbol90409$$libserver.dylib:
    0x8931f0e0 <+0>:    pushq  %rbp
    0x8931f0e1 <+1>:    movq   %rsp, %rbp
    0x8931f0e4 <+4>:    pushq  %r15
    0x8931f0e6 <+6>:    pushq  %r14
    0x8931f0e8 <+8>:    pushq  %r13
    0x8931f0ea <+10>:   pushq  %r12
    0x8931f0ec <+12>:   pushq  %rbx
    0x8931f0ed <+13>:   subq   $0x18, %rsp
    0x8931f0f1 <+17>:   movq   %rdi, %r15
    0x8931f0f4 <+20>:   movq   0xdca14d(%rip), %r13      ; (void *)0x0000000006bb6418: g_VProfCurrentProfile
    0x8931f0fb <+27>:   movl   0x1020(%r13), %r12d
    0x8931f102 <+34>:   testl  %r12d, %r12d
    0x8931f105 <+37>:   je     0x8931f1d7                ; <+247>
    0x8931f10b <+43>:   rdtsc  
    0x8931f10d <+45>:   movq   %rdx, %rbx
    0x8931f110 <+48>:   shlq   $0x20, %rbx
    0x8931f114 <+52>:   orq    %rax, %rbx
    0x8931f117 <+55>:   movq   0x1020(%r13), %rax
    0x8931f11e <+62>:   testl  %eax, %eax
    0x8931f120 <+64>:   jne    0x8931f131                ; <+81>
    0x8931f122 <+66>:   movabsq $0xff00000000, %rcx       ; imm = 0xFF00000000 
    0x8931f12c <+76>:   andq   %rcx, %rax
    0x8931f12f <+79>:   jne    0x8931f1a2                ; <+194>
    0x8931f131 <+81>:   movq   0x1e18(%r13), %r14
    0x8931f138 <+88>:   callq  0x89c883b4                ; symbol stub for: ThreadGetCurrentId
    0x8931f13d <+93>:   cmpq   %rax, %r14
    0x8931f140 <+96>:   jne    0x8931f1a2                ; <+194>
    0x8931f142 <+98>:   movq   0x1028(%r13), %rax
    0x8931f149 <+105>:  leaq   0xb8b5c9(%rip), %rcx      ; "CDOTA_TeamCommander::SendBotWorldStateToSocket"
    0x8931f150 <+112>:  cmpq   %rcx, (%rax)
    0x8931f153 <+115>:  je     0x8931f17a                ; <+154>
    0x8931f155 <+117>:  leaq   0xb8b5bd(%rip), %rsi      ; "CDOTA_TeamCommander::SendBotWorldStateToSocket"
    0x8931f15c <+124>:  leaq   0xb7d0b0(%rip), %rcx      ; "Bots"
    0x8931f163 <+131>:  xorl   %edx, %edx
    0x8931f165 <+133>:  movl   $0x4, %r8d
    0x8931f16b <+139>:  movq   %rax, %rdi
    0x8931f16e <+142>:  callq  0x89c88636                ; symbol stub for: CVProfNode::GetSubNode(char const*, int, char const*, int)
    0x8931f173 <+147>:  movq   %rax, 0x1028(%r13)
    0x8931f17a <+154>:  movslq 0x70(%rax), %rax
    0x8931f17e <+158>:  movq   0x10e0(%r13), %rcx
    0x8931f185 <+165>:  shlq   $0x4, %rax
    0x8931f189 <+169>:  orl    $0x4, 0x8(%rcx,%rax)
    0x8931f18e <+174>:  movq   0x1028(%r13), %rdi
    0x8931f195 <+181>:  callq  0x89c88630                ; symbol stub for: CVProfNode::EnterScope()
    0x8931f19a <+186>:  movb   $0x0, 0x1024(%r13)
    0x8931f1a2 <+194>:  rdtsc  
    0x8931f1a4 <+196>:  shlq   $0x20, %rdx
    0x8931f1a8 <+200>:  orq    %rax, %rdx
    0x8931f1ab <+203>:  subq   %rbx, %rdx
    0x8931f1ae <+206>:  movdqu 0x1010(%r13), %xmm0
    0x8931f1b7 <+215>:  movq   %rdx, %xmm1
    0x8931f1bc <+220>:  movl   $0x1, %eax
    0x8931f1c1 <+225>:  movq   %rax, %xmm2
    0x8931f1c6 <+230>:  punpcklqdq %xmm2, %xmm1              ; xmm1 = xmm1[0],xmm2[0]
    0x8931f1ca <+234>:  paddq  %xmm0, %xmm1
    0x8931f1ce <+238>:  movdqu %xmm1, 0x1010(%r13)
    0x8931f1d7 <+247>:  movq   0x11f0(%r15), %rdi
    0x8931f1de <+254>:  callq  0x892edb60                ; ___lldb_unnamed_symbol90248$$libserver.dylib
    0x8931f1e3 <+259>:  movq   0x11f0(%r15), %rbx
    0x8931f1ea <+266>:  cmpl   $-0x1, 0x8(%rbx)
    0x8931f1ee <+270>:  jne    0x8931f23c                ; <+348>
    0x8931f1f0 <+272>:  cmpl   $0x0, (%rbx)
    0x8931f1f3 <+275>:  je     0x8931f23c                ; <+348>
    0x8931f1f5 <+277>:  leaq   0x8(%rbx), %rsi
    0x8931f1f9 <+281>:  leaq   0x10(%rbx), %rdi
    0x8931f1fd <+285>:  leaq   -0x30(%rbp), %rdx
    0x8931f201 <+289>:  callq  0x89b34c50                ; ___lldb_unnamed_symbol148171$$libserver.dylib
    0x8931f206 <+294>:  testl  %eax, %eax
    0x8931f208 <+296>:  jne    0x8931f23c                ; <+348>
    0x8931f20a <+298>:  cmpq   $0x0, 0x70(%rbx)
    0x8931f20f <+303>:  jne    0x8931f23c                ; <+348>
    0x8931f211 <+305>:  cmpb   $0x0, 0xc(%rbx)
    0x8931f215 <+309>:  je     0x8931f23c                ; <+348>
    0x8931f217 <+311>:  movq   $0x0, (%rsp)
    0x8931f21f <+319>:  leaq   -0x31606(%rip), %rdi      ; ___lldb_unnamed_symbol90249$$libserver.dylib
    0x8931f226 <+326>:  xorl   %edx, %edx
    0x8931f228 <+328>:  xorl   %ecx, %ecx
    0x8931f22a <+330>:  xorl   %r8d, %r8d
    0x8931f22d <+333>:  xorl   %r9d, %r9d
    0x8931f230 <+336>:  movq   %rbx, %rsi
    0x8931f233 <+339>:  callq  0x89c88294                ; symbol stub for: CreateSimpleThread
    0x8931f238 <+344>:  movq   %rax, 0x70(%rbx)
    0x8931f23c <+348>:  movq   0x11f0(%r15), %rbx
    0x8931f243 <+355>:  movl   0x8(%rbx), %esi
    0x8931f246 <+358>:  cmpl   $-0x1, %esi
    0x8931f249 <+361>:  je     0x8931f463                ; <+899>
    0x8931f24f <+367>:  leaq   0x10(%rbx), %r14
    0x8931f253 <+371>:  movq   %r14, %rdi
    0x8931f256 <+374>:  callq  0x89b345f0                ; ___lldb_unnamed_symbol148161$$libserver.dylib
    0x8931f25b <+379>:  cmpl   $0x3, %eax
    0x8931f25e <+382>:  jne    0x8931f463                ; <+899>
    0x8931f264 <+388>:  movb   $0x0, -0x2a(%rbp)
    0x8931f268 <+392>:  movl   0x8(%rbx), %esi
    0x8931f26b <+395>:  leaq   0x19c5ad6(%rip), %rcx     ; pcre_stack_free + 1080
    0x8931f272 <+402>:  leaq   -0x2a(%rbp), %rdx
    0x8931f276 <+406>:  movl   $0x1, %r8d
    0x8931f27c <+412>:  movq   %r14, %rdi
    0x8931f27f <+415>:  callq  0x89b34470                ; ___lldb_unnamed_symbol148159$$libserver.dylib
    0x8931f284 <+420>:  testl  %eax, %eax
    0x8931f286 <+422>:  jne    0x8931f463                ; <+899>
    0x8931f28c <+428>:  cmpb   $0x0, -0x2a(%rbp)
    0x8931f290 <+432>:  je     0x8931f463                ; <+899>
    0x8931f296 <+438>:  movq   0x11f0(%r15), %r14
    0x8931f29d <+445>:  leaq   0x19f973c(%rip), %rax
    0x8931f2a4 <+452>:  movq   (%rax), %rax
    0x8931f2a7 <+455>:  movl   0x18(%rax), %eax
    0x8931f2aa <+458>:  cltd   
    0x8931f2ab <+459>:  idivl  0x4(%r14)
    0x8931f2af <+463>:  testl  %edx, %edx
    0x8931f2b1 <+465>:  jne    0x8931f463                ; <+899>
    0x8931f2b7 <+471>:  cmpb   $0x0, 0xc(%r14)
    0x8931f2bc <+476>:  jne    0x8931f2c7                ; <+487>
    0x8931f2be <+478>:  jmp    0x8931f322                ; <+578>
    0x8931f2c0 <+480>:  movq   0x11f0(%r15), %r14
    0x8931f2c7 <+487>:  cmpl   $0x0, 0x10078(%r14)
    0x8931f2cf <+495>:  je     0x8931f322                ; <+578>
    0x8931f2d1 <+497>:  movl   0x8(%r14), %esi
    0x8931f2d5 <+501>:  cmpl   $-0x1, %esi
    0x8931f2d8 <+504>:  je     0x8931f322                ; <+578>
    0x8931f2da <+506>:  leaq   0x10(%r14), %rbx
    0x8931f2de <+510>:  movq   %rbx, %rdi
    0x8931f2e1 <+513>:  callq  0x89b345f0                ; ___lldb_unnamed_symbol148161$$libserver.dylib
    0x8931f2e6 <+518>:  cmpl   $0x3, %eax
    0x8931f2e9 <+521>:  jne    0x8931f322                ; <+578>
    0x8931f2eb <+523>:  movb   $0x0, -0x29(%rbp)
    0x8931f2ef <+527>:  movl   0x8(%r14), %esi
    0x8931f2f3 <+531>:  movl   $0x1, %r8d
    0x8931f2f9 <+537>:  movq   %rbx, %rdi
    0x8931f2fc <+540>:  leaq   -0x29(%rbp), %rdx
    0x8931f300 <+544>:  leaq   0x19c5a41(%rip), %rcx     ; pcre_stack_free + 1080
    0x8931f307 <+551>:  callq  0x89b34470                ; ___lldb_unnamed_symbol148159$$libserver.dylib
    0x8931f30c <+556>:  testl  %eax, %eax
    0x8931f30e <+558>:  jne    0x8931f322                ; <+578>
    0x8931f310 <+560>:  cmpb   $0x0, -0x29(%rbp)
    0x8931f314 <+564>:  je     0x8931f322                ; <+578>
    0x8931f316 <+566>:  callq  0x89c883cc                ; symbol stub for: ThreadYield
    0x8931f31b <+571>:  jmp    0x8931f2c0                ; <+480>
    0x8931f31d <+573>:  jmp    0x8931f51e                ; <+1086>
    0x8931f322 <+578>:  leaq   0xf10(%r15), %r14
    0x8931f329 <+585>:  movq   %r15, %rdi
    0x8931f32c <+588>:  movq   %r14, %rsi
    0x8931f32f <+591>:  callq  0x8932fa30                ; ___lldb_unnamed_symbol90466$$libserver.dylib
    0x8931f334 <+596>:  leaq   0x1080(%r15), %rbx
    0x8931f33b <+603>:  movq   %r14, %rdi
    0x8931f33e <+606>:  movq   %rbx, %rsi
    0x8931f341 <+609>:  callq  0x8855d3b0                ; ___lldb_unnamed_symbol9268$$libserver.dylib
    0x8931f346 <+614>:  movq   %rbx, %rdi
    0x8931f349 <+617>:  callq  0x8855a570                ; ___lldb_unnamed_symbol9262$$libserver.dylib
    0x8931f34e <+622>:  movq   0x11f0(%r15), %rbx
    0x8931f355 <+629>:  leaq   0x78(%rbx), %rsi
    0x8931f359 <+633>:  movl   $0x10000, %edx            ; imm = 0x10000 
    0x8931f35e <+638>:  movq   %r14, %rdi
    0x8931f361 <+641>:  callq  0x89a7fabc                ; ___lldb_unnamed_symbol144614$$libserver.dylib
    0x8931f366 <+646>:  testb  %al, %al
    0x8931f368 <+648>:  jne    0x8931f378                ; <+664>
    0x8931f36a <+650>:  leaq   0xb85f81(%rip), %rdi      ; "Overflow in GetSerializedWorldState!\n"
    0x8931f371 <+657>:  xorl   %eax, %eax
    0x8931f373 <+659>:  callq  0x89c885f4                ; symbol stub for: DevWarning(char const*, ...)
    0x8931f378 <+664>:  movq   (%r14), %rax
    0x8931f37b <+667>:  movq   0x60(%rax), %rax
    0x8931f37f <+671>:  movq   %r14, %rdi
    0x8931f382 <+674>:  callq  *%rax
    0x8931f384 <+676>:  movl   %eax, 0x10078(%rbx)
    0x8931f38a <+682>:  cmpb   $0x0, 0xc(%rbx)
    0x8931f38e <+686>:  je     0x8931f390                ; <+688>
    0x8931f390 <+688>:  movq   0x11f0(%r15), %rdi
    0x8931f397 <+695>:  cmpb   $0x0, 0xc(%rdi)
    0x8931f39b <+699>:  jne    0x8931f3a2                ; <+706>
    0x8931f39d <+701>:  callq  0x892eda10                ; ___lldb_unnamed_symbol90247$$libserver.dylib
    0x8931f3a2 <+706>:  leaq   0x1b60157(%rip), %rdi
    0x8931f3a9 <+713>:  movl   $0x1, %esi
    0x8931f3ae <+718>:  callq  0x89c88b3a                ; symbol stub for: sigsetjmp
    0x8931f3b3 <+723>:  testl  %eax, %eax
    0x8931f3b5 <+725>:  je     0x8931f3ca                ; <+746>
    0x8931f3b7 <+727>:  cmpl   $0x2, 0x350(%r15)
    0x8931f3bf <+735>:  jne    0x8931f3f7                ; <+791>
    0x8931f3c1 <+737>:  leaq   0xb3144c(%rip), %rsi      ; "radiant"
    0x8931f3c8 <+744>:  jmp    0x8931f3fe                ; <+798>
    0x8931f3ca <+746>:  movq   0x1428(%r15), %rax
    0x8931f3d1 <+753>:  movq   0x18(%rax), %rcx
    0x8931f3d5 <+757>:  testq  %rcx, %rcx
    0x8931f3d8 <+760>:  je     0x8931f3e8                ; <+776>
    0x8931f3da <+762>:  movl   (%rax), %edi
    0x8931f3dc <+764>:  movq   %r14, %rsi
    0x8931f3df <+767>:  callq  *%rcx
    0x8931f3e1 <+769>:  movq   0x1428(%r15), %rax
    0x8931f3e8 <+776>:  movq   0x20(%rax), %rcx
    0x8931f3ec <+780>:  testq  %rcx, %rcx
    0x8931f3ef <+783>:  je     0x8931f463                ; <+899>
    0x8931f3f1 <+785>:  movl   (%rax), %edi
    0x8931f3f3 <+787>:  callq  *%rcx
    0x8931f3f5 <+789>:  jmp    0x8931f463                ; <+899>
    0x8931f3f7 <+791>:  leaq   0xb3141e(%rip), %rsi      ; "dire"
    0x8931f3fe <+798>:  leaq   0xb8b343(%rip), %rdi      ; "Segfault in %s bot API\n"
    0x8931f405 <+805>:  xorl   %eax, %eax
    0x8931f407 <+807>:  callq  0x89c88588                ; symbol stub for: Warning
    0x8931f40c <+812>:  movq   0x1428(%r15), %rbx
    0x8931f413 <+819>:  movq   0x28(%rbx), %rax
    0x8931f417 <+823>:  testq  %rax, %rax
    0x8931f41a <+826>:  je     0x8931f420                ; <+832>
    0x8931f41c <+828>:  movl   (%rbx), %edi
    0x8931f41e <+830>:  callq  *%rax
    0x8931f420 <+832>:  movq   0x8(%rbx), %rdi
    0x8931f424 <+836>:  testq  %rdi, %rdi
    0x8931f427 <+839>:  je     0x8931f453                ; <+883>
    0x8931f429 <+841>:  callq  0x89c889f0                ; symbol stub for: dlclose
    0x8931f42e <+846>:  testl  %eax, %eax
    0x8931f430 <+848>:  je     0x8931f44b                ; <+875>
    0x8931f432 <+850>:  callq  0x89c889f6                ; symbol stub for: dlerror
    0x8931f437 <+855>:  movq   %rax, %rcx
    0x8931f43a <+858>:  leaq   0xb85e91(%rip), %rdi      ; "Could not close old botcpp: %s\n"
    0x8931f441 <+865>:  xorl   %eax, %eax
    0x8931f443 <+867>:  movq   %rcx, %rsi
    0x8931f446 <+870>:  callq  0x89c88588                ; symbol stub for: Warning
    0x8931f44b <+875>:  movq   $0x0, 0x8(%rbx)
    0x8931f453 <+883>:  movq   $0x0, 0x20(%rbx)
    0x8931f45b <+891>:  movq   $0x0, 0x18(%rbx)
    0x8931f463 <+899>:  testl  %r12d, %r12d
    0x8931f466 <+902>:  je     0x8931f50f                ; <+1071>
    0x8931f46c <+908>:  rdtsc  
    0x8931f46e <+910>:  movq   %rdx, %rbx
    0x8931f471 <+913>:  shlq   $0x20, %rbx
    0x8931f475 <+917>:  orq    %rax, %rbx
    0x8931f478 <+920>:  cmpb   $0x0, 0x1024(%r13)
    0x8931f480 <+928>:  je     0x8931f48d                ; <+941>
    0x8931f482 <+930>:  movl   0x1020(%r13), %eax
    0x8931f489 <+937>:  testl  %eax, %eax
    0x8931f48b <+939>:  je     0x8931f4da                ; <+1018>
    0x8931f48d <+941>:  movq   0x1e18(%r13), %r14
    0x8931f494 <+948>:  callq  0x89c883b4                ; symbol stub for: ThreadGetCurrentId
    0x8931f499 <+953>:  cmpq   %rax, %r14
    0x8931f49c <+956>:  jne    0x8931f4da                ; <+1018>
    0x8931f49e <+958>:  movq   0x1028(%r13), %rdi
    0x8931f4a5 <+965>:  callq  0x89c88642                ; symbol stub for: CVProfNode::ExitScope()
    0x8931f4aa <+970>:  movq   0x1028(%r13), %rcx
    0x8931f4b1 <+977>:  testb  %al, %al
    0x8931f4b3 <+979>:  je     0x8931f4c8                ; <+1000>
    0x8931f4b5 <+981>:  movq   0x58(%rcx), %rax
    0x8931f4b9 <+985>:  testq  %rax, %rax
    0x8931f4bc <+988>:  je     0x8931f4c8                ; <+1000>
    0x8931f4be <+990>:  movq   %rax, 0x1028(%r13)
    0x8931f4c5 <+997>:  movq   %rax, %rcx
    0x8931f4c8 <+1000>: leaq   0x1030(%r13), %rax
    0x8931f4cf <+1007>: cmpq   %rax, %rcx
    0x8931f4d2 <+1010>: sete   0x1024(%r13)
    0x8931f4da <+1018>: rdtsc  
    0x8931f4dc <+1020>: shlq   $0x20, %rdx
    0x8931f4e0 <+1024>: orq    %rax, %rdx
    0x8931f4e3 <+1027>: subq   %rbx, %rdx
    0x8931f4e6 <+1030>: movdqu 0x1010(%r13), %xmm0
    0x8931f4ef <+1039>: movq   %rdx, %xmm1
    0x8931f4f4 <+1044>: movl   $0x1, %eax
    0x8931f4f9 <+1049>: movq   %rax, %xmm2
    0x8931f4fe <+1054>: punpcklqdq %xmm2, %xmm1              ; xmm1 = xmm1[0],xmm2[0]
    0x8931f502 <+1058>: paddq  %xmm0, %xmm1
    0x8931f506 <+1062>: movdqu %xmm1, 0x1010(%r13)
    0x8931f50f <+1071>: addq   $0x18, %rsp
    0x8931f513 <+1075>: popq   %rbx
    0x8931f514 <+1076>: popq   %r12
    0x8931f516 <+1078>: popq   %r13
    0x8931f518 <+1080>: popq   %r14
    0x8931f51a <+1082>: popq   %r15
    0x8931f51c <+1084>: popq   %rbp
    0x8931f51d <+1085>: retq   
    0x8931f51e <+1086>: movq   %rax, %r14
    0x8931f521 <+1089>: testl  %r12d, %r12d
    0x8931f524 <+1092>: je     0x8931f5d4                ; <+1268>
    0x8931f52a <+1098>: rdtsc  
    0x8931f52c <+1100>: movq   %rdx, %rbx
    0x8931f52f <+1103>: shlq   $0x20, %rbx
    0x8931f533 <+1107>: orq    %rax, %rbx
    0x8931f536 <+1110>: cmpb   $0x0, 0x1024(%r13)
    0x8931f53e <+1118>: je     0x8931f54b                ; <+1131>
    0x8931f540 <+1120>: movl   0x1020(%r13), %eax
    0x8931f547 <+1127>: testl  %eax, %eax
    0x8931f549 <+1129>: je     0x8931f598                ; <+1208>
    0x8931f54b <+1131>: movq   0x1e18(%r13), %r15
    0x8931f552 <+1138>: callq  0x89c883b4                ; symbol stub for: ThreadGetCurrentId
    0x8931f557 <+1143>: cmpq   %rax, %r15
    0x8931f55a <+1146>: jne    0x8931f598                ; <+1208>
    0x8931f55c <+1148>: movq   0x1028(%r13), %rdi
    0x8931f563 <+1155>: callq  0x89c88642                ; symbol stub for: CVProfNode::ExitScope()
    0x8931f568 <+1160>: movq   0x1028(%r13), %rcx
    0x8931f56f <+1167>: testb  %al, %al
    0x8931f571 <+1169>: je     0x8931f586                ; <+1190>
    0x8931f573 <+1171>: movq   0x58(%rcx), %rax
    0x8931f577 <+1175>: testq  %rax, %rax
    0x8931f57a <+1178>: je     0x8931f586                ; <+1190>
    0x8931f57c <+1180>: movq   %rax, 0x1028(%r13)
    0x8931f583 <+1187>: movq   %rax, %rcx
    0x8931f586 <+1190>: leaq   0x1030(%r13), %rax
    0x8931f58d <+1197>: cmpq   %rax, %rcx
    0x8931f590 <+1200>: sete   0x1024(%r13)
    0x8931f598 <+1208>: rdtsc  
    0x8931f59a <+1210>: jmp    0x8931f5a1                ; <+1217>
    0x8931f59c <+1212>: movq   %rax, %r14
    0x8931f59f <+1215>: rdtsc  
    0x8931f5a1 <+1217>: shlq   $0x20, %rdx
    0x8931f5a5 <+1221>: orq    %rax, %rdx
    0x8931f5a8 <+1224>: subq   %rbx, %rdx
    0x8931f5ab <+1227>: movdqu 0x1010(%r13), %xmm0
    0x8931f5b4 <+1236>: movq   %rdx, %xmm1
    0x8931f5b9 <+1241>: movl   $0x1, %eax
    0x8931f5be <+1246>: movq   %rax, %xmm2
    0x8931f5c3 <+1251>: punpcklqdq %xmm2, %xmm1              ; xmm1 = xmm1[0],xmm2[0]
    0x8931f5c7 <+1255>: paddq  %xmm0, %xmm1
    0x8931f5cb <+1259>: movdqu %xmm1, 0x1010(%r13)
    0x8931f5d4 <+1268>: movq   %r14, %rdi
    0x8931f5d7 <+1271>: callq  0x89c88942                ; symbol stub for: _Unwind_Resume
    0x8931f5dc <+1276>: movq   %rax, %rcx
    0x8931f5df <+1279>: rdtsc  
    0x8931f5e1 <+1281>: jmp    0x8931f5e8                ; <+1288>
    0x8931f5e3 <+1283>: movq   %rax, %rcx
    0x8931f5e6 <+1286>: rdtsc  
    0x8931f5e8 <+1288>: shlq   $0x20, %rdx
    0x8931f5ec <+1292>: orq    %rax, %rdx
    0x8931f5ef <+1295>: subq   %rbx, %rdx
    0x8931f5f2 <+1298>: movdqu 0x1010(%r13), %xmm0
    0x8931f5fb <+1307>: movq   %rdx, %xmm1
    0x8931f600 <+1312>: movl   $0x1, %eax
    0x8931f605 <+1317>: movq   %rax, %xmm2
    0x8931f60a <+1322>: punpcklqdq %xmm2, %xmm1              ; xmm1 = xmm1[0],xmm2[0]
    0x8931f60e <+1326>: paddq  %xmm0, %xmm1
    0x8931f612 <+1330>: movdqu %xmm1, 0x1010(%r13)
    0x8931f61b <+1339>: movq   %rcx, %rdi
    0x8931f61e <+1342>: callq  0x883c0460                ; ___lldb_unnamed_symbol3$$libserver.dylib
    0x8931f623 <+1347>: nopw   %cs:(%rax,%rax)

@Nostrademous
Copy link
Collaborator Author

It's also very much possible the 2nd argument is actually a pointer to an already created [empty] Actions protobuf...

I thought that too, but when I tried dumping it to string I would get a crash.

@Nostrademous
Copy link
Collaborator Author

Nostrademous commented Dec 20, 2018

screen shot 2018-12-20 at 12 57 04 pm
Still working on making sense of the code.

I believe Line #153 is call to Observe()
I believe Line #158 is call to Act()

@Nostrademous
Copy link
Collaborator Author

screen shot 2018-12-20 at 1 34 27 pm

@Nostrademous
Copy link
Collaborator Author

Nostrademous commented Dec 21, 2018

Regarding the first IDA image I posted (2 images above)

I believe Line #153 is call to Observe()
I believe Line #158 is call to Act()

@Nostrademous
Copy link
Collaborator Author

By the way... it looks like the intention is for us to be able to just call functions to take actions directly inside the Act(), and not use any protobuf. It just happens that in the Observe call the 2nd arg points the internal CMsgBot CLASS to the right offset so we sit at the WorldState implementation, but the class itself is full of virtual functions and other information.

When they pass the same data to Act() its probably for purposes of orientation but the intent might be to directly invoke using function pointers the appropriate actions using the provided class.

@Nostrademous
Copy link
Collaborator Author

Nostrademous commented Dec 21, 2018

The code is something like this:

      iteratePlayers(a1, *(double *)v17.m128_u64, *(double *)time_delta.m128i_i64);
      sub_F5ABE0(a1);
      sub_F5B1D0(a1);
      considerGlyph(a1);
      controlCourier(a1);
      calculateLaneFronts(a1);
      updatePotentialLocationGrid(a1);
      updateAvoidanceGrid(a1);
      if ( a1->gap354[725] > 0 )
      {
        v18 = 0;
        do
        {
          v19 = *(_QWORD *)&a1->gap354[727];
          v20 = 48LL * v18;
          v17.m128_f32[0] = sub_6908D0(v19 + v20 + 24);
          if ( v17.m128_f32[0] >= *(float *)(v19 + v20 + 36) )
          {
            v22 = a1->gap354[725];
            if ( a1->gap354[725] - v18 - 1 > 0 )
            {
              memmove(
                (void *)(*(_QWORD *)&a1->gap354[727] + v20),
                (const void *)(*(_QWORD *)&a1->gap354[727] + 48LL * (v18 + 1)),
                48LL * (a1->gap354[725] - v18 - 1));
              v22 = a1->gap354[725];
            }
            v21 = v22 - 1;
            a1->gap354[725] = v21;
            --v18;
          }
          else
          {
            v21 = a1->gap354[725];
          }
          ++v18;
        }
        while ( v18 < v21 );
      }
      if ( a1->gap354[731] > 0 )
      {
        v23 = 0;
        do
        {
          v24 = *(_QWORD *)&a1->gap354[733];
          v17 = (__m128)*(unsigned int *)(v24 + 8LL * v23 + 4);
          v25 = *(float *)(v24 + 8LL * v23 + 4);
          v17.m128_f32[0] = sub_A94280();
          if ( v17.m128_f32[0] <= v25 )
          {
            v27 = a1->gap354[731];
          }
          else
          {
            v26 = a1->gap354[731];
            if ( a1->gap354[731] - v23 - 1 > 0 )
            {
              memmove(
                (void *)(*(_QWORD *)&a1->gap354[733] + 8LL * v23),
                (const void *)(*(_QWORD *)&a1->gap354[733] + 8LL * (v23 + 1)),
                8LL * (a1->gap354[731] - v23 - 1));
              v26 = a1->gap354[731];
            }
            v27 = v26 - 1;
            a1->gap354[731] = v27;
            --v23;
          }
          ++v23;
        }
        while ( v23 < v27 );
      }
      setRuneInfo(a1, (__m128i)v17);
      callDynamicallyLoadedLibrary(a1, v28, (__m128)time_delta);
      execLuaBotThink(a1, "TeamThink", *(_QWORD *)&a1->gap354[975], 0LL, 0LL);
      updateLanePushDesires(a1);
      updateLaneDefendDesires(a1);
      updateFarmLaneDesires(a1);
      updateRoamDesires(a1, *(double *)v17.m128_u64, (__m128)time_delta, a5);
      updateRoshanDesire(a1, v17, (__m128)time_delta, a5);
      updateItemsDesire(a1);
      v29 = a1;
      sub_F690D0((struct_a1 *)((char *)a1 + 20), a1, *(double *)v17.m128_u64, *(double *)time_delta.m128i_i64);
      dota_time = a1->gap354[959];
      if ( *(float *)&dota_time >= 0.0 )
      {
        v31 = qword_299B380;
        if ( *(_DWORD *)(qword_299B380 + 920) == 4 )
        {
          if ( *(float *)&dota_time == 0.0 )
          {
            v32 = *(float *)(qword_299B380 + 2876);
            *(float *)&dota_time = v32 + RandomFloat(COERCE_DOUBLE(1084227584LL), COERCE_DOUBLE(1097859072LL));
            a1->gap354[959] = dota_time;
            v31 = qword_299B380;
          }
          if ( *(float *)(v31 + 2876) >= *(float *)&dota_time )
          {
            v29 = (struct_a1 *)"dota_chatwheel_message_GLHF";
            sub_F6B1E0(a1, "dota_chatwheel_message_GLHF", "", 0LL, 0LL);
            a1->gap354[959] = 3212836864;
          }
        }
      }

Our DLL sits inside the callDynamicallyLoadedLibrary Function

@TimZaman
Copy link
Owner

TimZaman commented Dec 21, 2018 via email

@Nostrademous
Copy link
Collaborator Author

Inside the callDynamicallyLoadedLibrary functions is a stub that eventually does:

            {
              baseFuncPtr = *(_QWORD *)&a1->CMsgBot[1077];
              Observe = *(void (__fastcall **)(__int64 *, int *))(baseFuncPtr + 0x18);
              if ( Observe )
              {
                libraryTeamID = (__int64 *)*(unsigned int *)baseFuncPtr;
                v21 = &a1->CMsgBot[751];
                Observe(libraryTeamID, &a1->CMsgBot[751]);
                baseFuncPtr = *(_QWORD *)&a1->CMsgBot[1077];
              }
              Act = *(__int64 (__fastcall **)(__int64 *, int *))(baseFuncPtr + 0x20);
              if ( Act )
              {
                libraryTeamID = (__int64 *)*(unsigned int *)baseFuncPtr;
                LODWORD(baseFuncPtr) = Act(libraryTeamID, v21);
              }
            }

@Nostrademous
Copy link
Collaborator Author

Nostrademous commented Dec 21, 2018

That would mean you need headers? And that wouldnt make much sense since its a dlopen..

You don't need headers, you just extern anything you want to call that exists somewhere else; and honestly, in reality most of those functions would be access via function pointers available inside the main CMsgBot class that's passed to us (we just don't know what offsets points to what yet).

@TimZaman
Copy link
Owner

TimZaman commented Mar 19, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants