AliceStats / Alice

Dota 2 replay parser written in C++
Apache License 2.0
78 stars 8 forks source link

[question] End of Game Stats #4

Closed ericp1337 closed 10 years ago

ericp1337 commented 10 years ago

Is there an easy way of just getting the end of game stats from the file? a proper wiki outlining how the lib works would be very helpful.

invokr commented 10 years ago

The examples are pretty straight forward and the code is fairly well documented. To get a summary, you want to handle the FileInfo Packet or look at the last entity state (specifically CGameRulesProxy and CPlayerRessource).

I modified the chat example to only print out the FileInfo packet: https://gist.github.com/invokr/9adc0b98254c58570eca

The only real important change, apart from changing the types according to the different packet, is that forward_dem needs to be set to true because FileInfo is a DEM Packet.

ericp1337 commented 10 years ago

I am able to now parse out the FileInfo packet from the end of the file, but I cannot seem to figure out how to parse out the combat log so I can generate the end of game stats screen such as KDA level and etc. I have looked at all examples, google, and been messing around with code but cannot seem to figure it out. any help is much appreciated.

I also tried to use the AliceSimple, but that throws a lot of errors when trying to compile.

invokr commented 10 years ago

I didn't know there were any problems compiling AliceSimple, but I haven't shown that project any love recently so yeah, it might be broken. It does not really fix what it is trying so solve though, a lightweight DSL would be better suited, but that is another topic.

Parsing the combat log and getting KDA / levels is something else entirely. To get the combatlog, do the following:

Each entry can be represented as the following structure:

struct combatlog_entry {
    /** Type of the combat log entry, e.g. damage etc*/
    uint8_t type;
    /** ID of the owner of the entity performing the action */
    int32_t sourcename;
    /** ID of the target*/
    int32_t targetname;
    /** ID of the attacker */
    int32_t attackername;
    /** ID of the buf / debug inflicted*/
    int32_t inflictorname;
    /** is attacker an illusion */
    bool attackerillusion;
    /** is target an illusion */
    bool targetillusion;
    /** hp lost / gained*/
    int32_t value;
    /** hp after the action was made*/
    int32_t health;
    /** time this occured */
    float timestamp;
    /** owner id of the target entity*/
    uint32_t targetsourcename;
};

Hence you can get it's values something like this (from the game event packet):

combatlog_entry e{
    event->keys(0).val_byte(),
    event->keys(1).val_short(), event->keys(2).val_short(),   
    event->keys(3).val_short(), event->keys(4).val_short(), 
    event->keys(5).val_bool(), event->keys(6).val_bool(), 
    event->keys(7).val_short(), event->keys(8).val_short(), 
    event->keys(9).val_float(), event->keys(10).val_short() 
};

Next up would be getting KDA / LH etc.You need to grep these out of the entities along the lines of:

Your code could look like this:

// earlier
parser* p;

// in the function that receives the `FileInfo` Packet
uint32_t prId = p->getEntityIdFor("CDOTA_PlayerRessource");
uint32_t gId = p->getEntityIdFor("CDOTAGameRulesProxy");

auto entities = p->getEntities();

for (auto &e : entities) {
    if (e.isInitialized() && e.getClassId() == prId) {
        // Player Ressource, example: Get the number of kills for the first player
        uint32_t kills_player_1 = e.prop<uint32_t>(".m_iKills.0000");
    } else if (e.isInitialized() && e.getClassId() == gId) {
        // Game Rules proxy, example: Get game winner:
        float time = e.prop<float>(".dota_gamerules_data.m_fGameTime");
    }
}

If you are unsure what property types certain entities are, or which are available at all, look at the devkit. It provides a nice overview over different entity types and values.