update
This commit is contained in:
parent
e41bb63fbd
commit
9533b13806
227
main.go
227
main.go
@ -19,30 +19,38 @@ type Team struct {
|
||||
}
|
||||
|
||||
type PlayerStats struct {
|
||||
Name string `json:"name"`
|
||||
SteamID string `json:"steamId"`
|
||||
Team string `json:"team"`
|
||||
Kills int `json:"kills"`
|
||||
Deaths int `json:"deaths"`
|
||||
Assists int `json:"assists"`
|
||||
FlashAssists int `json:"flashAssists"`
|
||||
TotalDamage int `json:"totalDamage"`
|
||||
UtilityDamage int `json:"utilityDamage"`
|
||||
MVPs int `json:"mvps"`
|
||||
MVPReason1 int `json:"mvpEliminations"`
|
||||
MVPReason2 int `json:"mvpDefuse"`
|
||||
MVPReason3 int `json:"mvpPlant"`
|
||||
KnifeKills int `json:"knifeKills"`
|
||||
ZeusKills int `json:"zeusKills"`
|
||||
WallbangKills int `json:"wallbangKills"`
|
||||
SmokeKills int `json:"smokeKills"`
|
||||
Headshots int `json:"headshots"`
|
||||
NoScopes int `json:"noScopes"`
|
||||
BlindKills int `json:"blindKills"`
|
||||
RankOld int `json:"rankOld,omitempty"`
|
||||
RankNew int `json:"rankNew,omitempty"`
|
||||
RankChange int `json:"rankChange,omitempty"`
|
||||
WinCount int `json:"winCount,omitempty"`
|
||||
Name string `json:"name"`
|
||||
SteamID string `json:"steamId"`
|
||||
Team string `json:"team"`
|
||||
Kills int `json:"kills"`
|
||||
Deaths int `json:"deaths"`
|
||||
Assists int `json:"assists"`
|
||||
FlashAssists int `json:"flashAssists"`
|
||||
TotalDamage int `json:"totalDamage"`
|
||||
UtilityDamage int `json:"utilityDamage"`
|
||||
MVPs int `json:"mvps"`
|
||||
MVPReason1 int `json:"mvpEliminations"`
|
||||
MVPReason2 int `json:"mvpDefuse"`
|
||||
MVPReason3 int `json:"mvpPlant"`
|
||||
KnifeKills int `json:"knifeKills"`
|
||||
ZeusKills int `json:"zeusKills"`
|
||||
WallbangKills int `json:"wallbangKills"`
|
||||
SmokeKills int `json:"smokeKills"`
|
||||
Headshots int `json:"headshots"`
|
||||
NoScopes int `json:"noScopes"`
|
||||
BlindKills int `json:"blindKills"`
|
||||
RankOld int `json:"rankOld,omitempty"`
|
||||
RankNew int `json:"rankNew,omitempty"`
|
||||
RankChange int `json:"rankChange,omitempty"`
|
||||
WinCount int `json:"winCount,omitempty"`
|
||||
OneK int `json:"oneK"`
|
||||
TwoK int `json:"twoK"`
|
||||
ThreeK int `json:"threeK"`
|
||||
FourK int `json:"fourK"`
|
||||
FiveK int `json:"fiveK"`
|
||||
ShotsFired int `json:"shotsFired"`
|
||||
ShotsHit int `json:"shotsHit"`
|
||||
Aim float64 `json:"aim"` // Prozent
|
||||
}
|
||||
|
||||
type RoundResult struct {
|
||||
@ -107,6 +115,22 @@ func parseSteamID(id string) (uint64, error) {
|
||||
return sid, err
|
||||
}
|
||||
|
||||
// Bullet-Waffen (Schusswaffen) erkennen – keine Nades/Knife/Zeus/Equipment
|
||||
func isBulletWeapon(eq *common.Equipment) bool {
|
||||
if eq == nil {
|
||||
return false
|
||||
}
|
||||
switch eq.Type {
|
||||
case common.EqKnife, common.EqZeus, common.EqHE, common.EqMolotov, common.EqIncendiary, common.EqFlash, common.EqSmoke, common.EqDecoy:
|
||||
return false
|
||||
}
|
||||
cls := eq.Class()
|
||||
if cls == common.EqClassGrenade || cls == common.EqClassEquipment {
|
||||
return false
|
||||
}
|
||||
return true // Pistols/SMG/Rifles/Heavy/Sniper
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
fmt.Println("❌ Demo-Datei fehlt")
|
||||
@ -129,18 +153,23 @@ func main() {
|
||||
var roundHistory []RoundResult
|
||||
var teamHistory = make(PlayerTeamHistory)
|
||||
|
||||
// Per-Runde Kills, die bis zum *nächsten* RoundStart gehalten werden
|
||||
var roundKills = make(map[uint64]int) // SteamID64 -> Kills in der aktuellen (zuletzt gestarteten) Runde
|
||||
var haveOpenRound bool // true ab erstem RoundStart nach MatchStart
|
||||
var lastNonSpecTeam = make(map[uint64]string) // "CT" oder "T"
|
||||
|
||||
if len(os.Args) >= 3 {
|
||||
inputId := os.Args[2]
|
||||
_, err := fmt.Sscanf(inputId, "%d", &matchId)
|
||||
if err != nil {
|
||||
fmt.Printf("⚠️ Ungültige matchId-Argument: %v\n", err)
|
||||
fmt.Printf("⚠️ Ungültiges matchId-Argument: %v\n", err)
|
||||
matchId = 0
|
||||
}
|
||||
}
|
||||
|
||||
p.RegisterNetMessageHandler(func(msg *msg.CSVCMsg_ServerInfo) {
|
||||
if msg != nil && msg.GetMapName() != "" {
|
||||
mapName = msg.GetMapName()
|
||||
p.RegisterNetMessageHandler(func(m *msg.CSVCMsg_ServerInfo) {
|
||||
if m != nil && m.GetMapName() != "" {
|
||||
mapName = m.GetMapName()
|
||||
}
|
||||
})
|
||||
|
||||
@ -166,17 +195,79 @@ func main() {
|
||||
return stat
|
||||
}
|
||||
|
||||
p.RegisterEventHandler(func(e events.RoundStart) {
|
||||
round := roundCount + 1 // nächste Runde
|
||||
teamHistory[round] = map[uint64]string{}
|
||||
|
||||
for _, p := range p.GameState().Participants().Playing() {
|
||||
if p.Team == common.TeamCounterTerrorists {
|
||||
teamHistory[round][p.SteamID64] = "CT"
|
||||
} else if p.Team == common.TeamTerrorists {
|
||||
teamHistory[round][p.SteamID64] = "T"
|
||||
// Hilfsfunktion: roundKills -> 1k/2k/3k/4k/5k übertragen
|
||||
flushRoundKills := func() {
|
||||
for sid, k := range roundKills {
|
||||
stat := playerStats[sid]
|
||||
if stat == nil {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case k == 1:
|
||||
stat.OneK++
|
||||
case k == 2:
|
||||
stat.TwoK++
|
||||
case k == 3:
|
||||
stat.ThreeK++
|
||||
case k == 4:
|
||||
stat.FourK++
|
||||
case k >= 5:
|
||||
stat.FiveK++
|
||||
}
|
||||
}
|
||||
roundKills = make(map[uint64]int)
|
||||
}
|
||||
|
||||
p.RegisterEventHandler(func(e events.RoundStart) {
|
||||
if !p.GameState().IsMatchStarted() {
|
||||
return
|
||||
}
|
||||
|
||||
if haveOpenRound {
|
||||
flushRoundKills()
|
||||
}
|
||||
haveOpenRound = true
|
||||
|
||||
round := roundCount + 1
|
||||
teamHistory[round] = map[uint64]string{}
|
||||
for _, pl := range p.GameState().Participants().Playing() {
|
||||
switch pl.Team {
|
||||
case common.TeamCounterTerrorists:
|
||||
teamHistory[round][pl.SteamID64] = "CT"
|
||||
lastNonSpecTeam[pl.SteamID64] = "CT"
|
||||
case common.TeamTerrorists:
|
||||
teamHistory[round][pl.SteamID64] = "T"
|
||||
lastNonSpecTeam[pl.SteamID64] = "T"
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
p.RegisterEventHandler(func(e events.PlayerTeamChange) {
|
||||
if e.Player == nil {
|
||||
return
|
||||
}
|
||||
sid := e.Player.SteamID64
|
||||
// Nur Nicht-Spectator übernehmen; Spectator/Unassigned löscht NICHT den letzten Stand
|
||||
switch e.NewTeam {
|
||||
case common.TeamCounterTerrorists:
|
||||
lastNonSpecTeam[sid] = "CT"
|
||||
case common.TeamTerrorists:
|
||||
lastNonSpecTeam[sid] = "T"
|
||||
}
|
||||
})
|
||||
|
||||
// Schüsse zählen (nur Schusswaffen)
|
||||
p.RegisterEventHandler(func(e events.WeaponFire) {
|
||||
if !haveOpenRound {
|
||||
return // Warmup ignorieren
|
||||
}
|
||||
if e.Shooter == nil || e.Weapon == nil {
|
||||
return
|
||||
}
|
||||
if !isBulletWeapon(e.Weapon) {
|
||||
return
|
||||
}
|
||||
getOrCreate(*e.Shooter).ShotsFired++
|
||||
})
|
||||
|
||||
p.RegisterEventHandler(func(e events.Kill) {
|
||||
@ -187,6 +278,12 @@ func main() {
|
||||
if killerTeam != victimTeam && killerTeam != common.TeamSpectators {
|
||||
stat := getOrCreate(*e.Killer)
|
||||
stat.Kills++
|
||||
|
||||
// Nur zählen, wenn wir uns in/zwischen echten Runden befinden
|
||||
if haveOpenRound {
|
||||
roundKills[e.Killer.SteamID64]++
|
||||
}
|
||||
|
||||
if e.IsHeadshot {
|
||||
stat.Headshots++
|
||||
}
|
||||
@ -214,32 +311,39 @@ func main() {
|
||||
}
|
||||
|
||||
if e.Victim != nil {
|
||||
stat := getOrCreate(*e.Victim)
|
||||
stat.Deaths++
|
||||
getOrCreate(*e.Victim).Deaths++
|
||||
}
|
||||
|
||||
if e.Assister != nil {
|
||||
stat := getOrCreate(*e.Assister)
|
||||
stat.Assists++
|
||||
getOrCreate(*e.Assister).Assists++
|
||||
}
|
||||
})
|
||||
|
||||
p.RegisterEventHandler(func(e events.PlayerFlashed) {
|
||||
if e.Attacker != nil && e.Attacker.SteamID64 != e.Player.SteamID64 {
|
||||
stat := getOrCreate(*e.Attacker)
|
||||
stat.FlashAssists++
|
||||
getOrCreate(*e.Attacker).FlashAssists++
|
||||
}
|
||||
})
|
||||
|
||||
p.RegisterEventHandler(func(e events.PlayerHurt) {
|
||||
if e.Attacker != nil && e.Attacker != e.Player {
|
||||
stat := getOrCreate(*e.Attacker)
|
||||
|
||||
// Utility-Damage separat zählen
|
||||
if e.Weapon != nil {
|
||||
switch e.Weapon.Type {
|
||||
case common.EqHE, common.EqMolotov, common.EqIncendiary:
|
||||
stat.UtilityDamage += e.HealthDamage
|
||||
}
|
||||
}
|
||||
|
||||
// Treffer (nur Schusswaffen, nur Gegner, nur echte Runden)
|
||||
if haveOpenRound && e.HealthDamage > 0 && e.Weapon != nil && isBulletWeapon(e.Weapon) {
|
||||
attTeam := e.Attacker.Team
|
||||
vicTeam := e.Player.Team
|
||||
if attTeam != vicTeam && attTeam != common.TeamSpectators {
|
||||
stat.ShotsHit++
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@ -259,6 +363,7 @@ func main() {
|
||||
})
|
||||
|
||||
p.RegisterEventHandler(func(e events.RoundEnd) {
|
||||
// Scores & Round-History wie gehabt
|
||||
scoreCT = p.GameState().TeamCounterTerrorists().Score()
|
||||
scoreT = p.GameState().TeamTerrorists().Score()
|
||||
roundCount++
|
||||
@ -278,6 +383,7 @@ func main() {
|
||||
Winner: winner,
|
||||
WinReason: reasonToString(e.Reason),
|
||||
})
|
||||
// KEIN flush hier! Nach-Runden-Kills sollen noch in diese Runde fallen.
|
||||
})
|
||||
|
||||
p.RegisterEventHandler(func(e events.RankUpdate) {
|
||||
@ -296,6 +402,11 @@ func main() {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Letztes Flush falls Match endet ohne weiteren RoundStart
|
||||
if haveOpenRound && len(roundKills) > 0 {
|
||||
flushRoundKills()
|
||||
}
|
||||
|
||||
teamAName := p.GameState().TeamCounterTerrorists().ClanName()
|
||||
if teamAName == "" {
|
||||
teamAName = "CT"
|
||||
@ -307,32 +418,44 @@ func main() {
|
||||
|
||||
for _, stat := range playerStats {
|
||||
sid, _ := parseSteamID(stat.SteamID)
|
||||
|
||||
if t, ok := lastNonSpecTeam[sid]; ok && (t == "CT" || t == "T") {
|
||||
stat.Team = t
|
||||
continue
|
||||
}
|
||||
|
||||
// Fallback: letzter Runden-Eintrag aus teamHistory
|
||||
lastTeam := ""
|
||||
lastRound := 0
|
||||
|
||||
for roundNum, roundTeams := range teamHistory {
|
||||
if team, ok := roundTeams[sid]; ok && roundNum > lastRound {
|
||||
lastTeam = team
|
||||
lastRound = roundNum
|
||||
}
|
||||
}
|
||||
|
||||
stat.Team = lastTeam
|
||||
}
|
||||
|
||||
for _, player := range p.GameState().Participants().All() {
|
||||
sid := player.SteamID64
|
||||
for _, pl := range p.GameState().Participants().All() {
|
||||
sid := pl.SteamID64
|
||||
stat, ok := playerStats[sid]
|
||||
if !ok || player.Entity == nil {
|
||||
if !ok || pl.Entity == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
val, ok := player.Entity.PropertyValue("m_pActionTrackingServices.m_iDamage")
|
||||
if ok {
|
||||
if val, ok := pl.Entity.PropertyValue("m_pActionTrackingServices.m_iDamage"); ok {
|
||||
stat.TotalDamage = val.Int()
|
||||
}
|
||||
}
|
||||
|
||||
// Aim-Wert berechnen
|
||||
for _, stat := range playerStats {
|
||||
if stat.ShotsFired > 0 {
|
||||
stat.Aim = sanitizeFloat(float64(stat.ShotsHit) * 100.0 / float64(stat.ShotsFired))
|
||||
} else {
|
||||
stat.Aim = 0
|
||||
}
|
||||
}
|
||||
|
||||
var ctPlayers, tPlayers []PlayerStats
|
||||
for _, stat := range playerStats {
|
||||
switch stat.Team {
|
||||
|
||||
BIN
parser_cs2-linux
BIN
parser_cs2-linux
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user