This commit is contained in:
Linrador 2025-06-11 06:15:57 +02:00
parent 85d13c60fd
commit b316d1f7a6
3 changed files with 114 additions and 15 deletions

107
main.go
View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"math" "math"
"os" "os"
"time"
demoinfocs "github.com/markus-wa/demoinfocs-golang/v4/pkg/demoinfocs" demoinfocs "github.com/markus-wa/demoinfocs-golang/v4/pkg/demoinfocs"
"github.com/markus-wa/demoinfocs-golang/v4/pkg/demoinfocs/common" "github.com/markus-wa/demoinfocs-golang/v4/pkg/demoinfocs/common"
@ -30,18 +31,32 @@ type PlayerStats struct {
Headshots int `json:"headshots"` Headshots int `json:"headshots"`
NoScopes int `json:"noScopes"` NoScopes int `json:"noScopes"`
BlindKills int `json:"blindKills"` BlindKills int `json:"blindKills"`
RankOld int `json:"rankOld,omitempty"` RankOld int `json:"rankOld,omitempty"`
RankNew int `json:"rankNew,omitempty"` RankNew int `json:"rankNew,omitempty"`
RankChange int `json:"rankChange,omitempty"`
WinCount int `json:"winCount,omitempty"` WinCount int `json:"winCount,omitempty"`
} }
type RoundResult struct {
Round int `json:"round"`
Winner string `json:"winner"`
WinReason string `json:"winReason"`
}
type DemoMeta struct { type DemoMeta struct {
MatchID uint64 `json:"matchId"` MatchID uint64 `json:"matchId"`
Map string `json:"map"` Map string `json:"map"`
Players []PlayerStats `json:"players"` Players []PlayerStats `json:"players"`
Duration float64 `json:"duration"` Duration float64 `json:"duration"`
TickRate float64 `json:"tickRate"` TickRate float64 `json:"tickRate"`
ScoreCT int `json:"scoreCT"`
ScoreT int `json:"scoreT"`
TeamCT string `json:"teamCT"`
TeamT string `json:"teamT"`
WinnerTeam string `json:"winnerTeam"`
RoundCount int `json:"roundCount"`
RoundHistory []RoundResult `json:"roundHistory"`
DemoDate string `json:"demoDate"`
} }
func sanitizeFloat(value float64) float64 { func sanitizeFloat(value float64) float64 {
@ -51,6 +66,43 @@ func sanitizeFloat(value float64) float64 {
return value return value
} }
func getDemoTimestamp(path string) string {
info, err := os.Stat(path)
if err != nil {
return ""
}
return info.ModTime().UTC().Format("2006-01-02T15:04:05Z")
}
func reasonToString(reason events.RoundEndReason) string {
switch reason {
case events.RoundEndReasonTargetBombed:
return "Bomb"
case events.RoundEndReasonTerroristsStopped:
return "T eliminated"
case events.RoundEndReasonCTStoppedEscape:
return "CT stopped escape"
case events.RoundEndReasonTerroristsEscaped:
return "T escaped"
case events.RoundEndReasonHostagesRescued:
return "Hostages rescued"
case events.RoundEndReasonCTWin:
return "CT win"
case events.RoundEndReasonTerroristsWin:
return "T win"
case events.RoundEndReasonDraw:
return "Draw"
case events.RoundEndReasonHostagesNotRescued:
return "Hostages not rescued"
case events.RoundEndReasonTerroristsNotEscaped:
return "T not escaped"
case events.RoundEndReasonBombDefused:
return "Bomb defused"
default:
return "Unknown"
}
}
func main() { func main() {
if len(os.Args) < 2 { if len(os.Args) < 2 {
fmt.Println("❌ Demo-Datei fehlt") fmt.Println("❌ Demo-Datei fehlt")
@ -69,6 +121,8 @@ func main() {
var mapName string var mapName string
var matchId uint64 var matchId uint64
var scoreCT, scoreT, roundCount int
var roundHistory []RoundResult
if len(os.Args) >= 3 { if len(os.Args) >= 3 {
inputId := os.Args[2] inputId := os.Args[2]
@ -79,7 +133,6 @@ func main() {
} }
} }
// Hole Mapname aus ServerInfo (zuverlässiger als Header.MapName)
p.RegisterNetMessageHandler(func(msg *msg.CSVCMsg_ServerInfo) { p.RegisterNetMessageHandler(func(msg *msg.CSVCMsg_ServerInfo) {
if msg != nil && msg.GetMapName() != "" { if msg != nil && msg.GetMapName() != "" {
mapName = msg.GetMapName() mapName = msg.GetMapName()
@ -166,12 +219,34 @@ func main() {
} }
}) })
// 📊 Premier Rank / Elo Veränderung p.RegisterEventHandler(func(e events.RoundEnd) {
scoreCT = p.GameState().TeamCounterTerrorists().Score()
scoreT = p.GameState().TeamTerrorists().Score()
roundCount++
var winner string
switch e.Winner {
case common.TeamTerrorists:
winner = "T"
case common.TeamCounterTerrorists:
winner = "CT"
default:
winner = "Unknown"
}
roundHistory = append(roundHistory, RoundResult{
Round: roundCount,
Winner: winner,
WinReason: reasonToString(e.Reason),
})
})
p.RegisterEventHandler(func(e events.RankUpdate) { p.RegisterEventHandler(func(e events.RankUpdate) {
if e.Player != nil { if e.Player != nil {
stat := getOrCreate(e.Player.SteamID64, e.Player.Name) stat := getOrCreate(e.Player.SteamID64, e.Player.Name)
stat.RankOld = e.RankOld stat.RankOld = e.RankOld
stat.RankNew = e.RankNew stat.RankNew = e.RankNew
stat.RankChange = int(e.RankChange)
stat.WinCount = e.WinCount stat.WinCount = e.WinCount
} }
}) })
@ -182,13 +257,29 @@ func main() {
os.Exit(1) os.Exit(1)
} }
teamCT := p.GameState().TeamCounterTerrorists().ClanName()
teamT := p.GameState().TeamTerrorists().ClanName()
scoreCT = p.GameState().TeamCounterTerrorists().Score()
scoreT = p.GameState().TeamTerrorists().Score()
winnerTeam := "Draw"
if scoreCT > scoreT {
winnerTeam = teamCT
} else if scoreT > scoreCT {
winnerTeam = teamT
}
demoDate := getDemoTimestamp(filePath)
if demoDate == "" {
demoDate = time.Now().UTC().Format("2006-01-02T15:04:05Z")
}
duration := sanitizeFloat(header.PlaybackTime.Seconds()) duration := sanitizeFloat(header.PlaybackTime.Seconds())
tickRate := 0.0 tickRate := 0.0
if duration > 0 { if duration > 0 {
tickRate = sanitizeFloat(float64(header.PlaybackTicks) / duration) tickRate = sanitizeFloat(float64(header.PlaybackTicks) / duration)
} }
// Fallback auf Header-Map, falls kein ServerInfo-Mapname verfügbar
if mapName == "" { if mapName == "" {
mapName = header.MapName mapName = header.MapName
} }
@ -198,6 +289,14 @@ func main() {
Map: mapName, Map: mapName,
Duration: duration, Duration: duration,
TickRate: tickRate, TickRate: tickRate,
ScoreCT: scoreCT,
ScoreT: scoreT,
TeamCT: teamCT,
TeamT: teamT,
WinnerTeam: winnerTeam,
RoundCount: roundCount,
RoundHistory: roundHistory,
DemoDate: demoDate,
} }
for _, stat := range playerStats { for _, stat := range playerStats {

Binary file not shown.

Binary file not shown.