Skip to content

How do I get the game start time (00:00) from a Dota 2 .dem file? #176

Description

@D2hugging

Hi, everyone! I want to use the Dota client console command demo_gototick to precisely position the replay to just before the teamfight start time. The teamfight start time is relative to the game clock at 00:00, but .dem files include BP time, game preparation countdown (90s), and even pauses. I'm parsing .dem files using Go's Manta library with the following code:
package main

import (
    "fmt"
    "log"
    "os"



    "github.com/dotabuff/manta"
    "github.com/dotabuff/manta/dota"
)



const (
    DOTA_GAMERULES_STATE_GAME_IN_PROGRESS = 5
)



func main() {
    if len(os.Args) < 2 {
        fmt.Println("Usage: go run main.go <demo.dem>")
        return
    }



    f, err := os.Open(os.Args[1])
    if err != nil {
        log.Fatalf("can't open file: %v", err)
    }
    defer f.Close()



    p, err := manta.NewStreamParser(f)
    if err != nil {
        log.Fatalf("can't create parser: %v", err)
    }



    found := false



    // GamerulesStateChanged callback
    p.Callbacks.OnCDOTAUserMsg_GamerulesStateChanged(
        func(m *dota.CDOTAUserMsg_GamerulesStateChanged) error {



            state := m.GetState()
            tick := p.NetTick
            
            log.Printf("[GamerulesStateChanged] state=%d tick=%d", state, tick)



            if !found && state == DOTA_GAMERULES_STATE_GAME_IN_PROGRESS {
                log.Println("========================================")
                log.Println("get  GAME_IN_PROGRESS(00:00)")
                log.Printf("Absolute Tick: %d", tick)
                
                log.Printf("Demo time: %.3f s", float64(tick)/30.0)
                log.Println("========================================")



                found = true
                p.Stop()
            }
            return nil
        },
    )


    log.Println("begin to parse demo, waiting for GAME_IN_PROGRESS (00:00)")
    err = p.Start()



    if err != nil && err.Error() != "stop" && err.Error() != "stopped" {
        log.Fatalf("failed to parse: %v", err)
    }



    if !found {
        log.Println("Not found GAME_IN_PROGRESS")
    }
}

go run ./main.go ./8598826514_1751608472.dem
After running the above code, the output is as follows:

2026/01/08 21:52:31 begin to parse demo, waiting for GAME_IN_PROGRESS (00:00)
2026/01/08 21:52:31 [GamerulesStateChanged] state=2 tick=486
2026/01/08 21:52:31 [GamerulesStateChanged] state=12 tick=486
2026/01/08 21:52:31 [GamerulesStateChanged] state=9 tick=486
2026/01/08 21:52:31 [GamerulesStateChanged] state=3 tick=3131
2026/01/08 21:52:31 [GamerulesStateChanged] state=8 tick=4031
2026/01/08 21:52:31 [GamerulesStateChanged] state=4 tick=4514
2026/01/08 21:52:31 [GamerulesStateChanged] state=10 tick=4514
2026/01/08 21:52:31 [GamerulesStateChanged] state=5 tick=7214
2026/01/08 21:52:31 ========================================
2026/01/08 21:52:31 get GAME_IN_PROGRESS(00:00)
2026/01/08 21:52:31 Absolute Tick: 7214
2026/01/08 21:52:31 Demo time: 240.467 s
2026/01/08 21:52:31 ========================================

Match ID 8598826514 enters GAME_IN_PROGRESS state at tick 7214 according to the logs. I expected demo_gototick 7214 to precisely position at game start (00:00), but testing shows it actually jumps to around the pre-game countdown (01:30). Is there an issue with my code, or did I misunderstand the GAME_IN_PROGRESS state timing? Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions