update to new go-steam version

This commit is contained in:
2025-10-26 05:20:47 +01:00
parent ab8b0b983c
commit df22705679
8 changed files with 364 additions and 312 deletions

View File

@@ -3,6 +3,11 @@ package csgo
import (
"context"
"fmt"
"os"
"strings"
"sync"
"time"
"github.com/an0nfunc/go-steam/v3"
"github.com/an0nfunc/go-steam/v3/csgo/protocol/protobuf"
"github.com/an0nfunc/go-steam/v3/protocol/gamecoordinator"
@@ -13,12 +18,8 @@ import (
log "github.com/sirupsen/logrus"
"golang.org/x/time/rate"
"google.golang.org/protobuf/proto"
"os"
"somegit.dev/csgowtf/csgowtfd/ent"
"somegit.dev/csgowtf/csgowtfd/utils"
"strings"
"sync"
"time"
)
const (
@@ -61,24 +62,38 @@ type DemoMatchLoader struct {
LoggedIn bool
}
type PlayerRoundStats struct {
Kills int32
Deaths int32
Assists int32
Headshots int32
Score int32
MPVs int32
}
func AccountID2SteamID(accID uint32) uint64 {
return uint64(accID) + 76561197960265728 //nolint:gomnd
}
func SteamID2AccountID(steamID uint64) uint32 {
return uint32(steamID - 76561197960265728) //nolint:gomnd
return uint32(steamID - 76561197960265728) //nolint:gosec,gomnd
}
func playerStatsFromRound(round *protobuf.CMsgGCCStrike15V2_MatchmakingServerRoundStats, p *ent.Player) (kills int32,
deaths int32, assists int32, headshots int32, score int32, mvps int32) {
func playerStatsFromRound(round *protobuf.CMsgGCCStrike15V2_MatchmakingServerRoundStats, p *ent.Player) PlayerRoundStats {
for i, acc := range round.GetReservation().GetAccountIds() {
if AccountID2SteamID(acc) == p.ID {
return round.GetKills()[i], round.GetDeaths()[i], round.GetAssists()[i], round.GetEnemyHeadshots()[i],
round.GetScores()[i], round.GetMvps()[i]
return PlayerRoundStats{
Kills: round.GetKills()[i],
Deaths: round.GetDeaths()[i],
Assists: round.GetAssists()[i],
Headshots: round.GetEnemyHeadshots()[i],
Score: round.GetScores()[i],
MPVs: round.GetMvps()[i],
}
}
}
return 0, 0, 0, 0, 0, 0
return PlayerRoundStats{}
}
func (dml *DemoMatchLoader) IsLoading(demo *Demo) bool {
@@ -146,7 +161,7 @@ func (dml *DemoMatchLoader) HandleGCPacket(pkg *gamecoordinator.GCPacket) {
func (dml *DemoMatchLoader) getMatchDetails(sharecode string) (*protobuf.CMsgGCCStrike15V2_MatchList, error) {
if !dml.GCReady {
return nil, fmt.Errorf("gc not ready")
return nil, errors.New("gc not ready")
}
matchID, outcomeID, tokenID, err := DecodeSharecode(sharecode)
@@ -159,7 +174,7 @@ func (dml *DemoMatchLoader) getMatchDetails(sharecode string) (*protobuf.CMsgGCC
}
for matchDetails := range dml.matchRecv {
if *matchDetails.Matches[0].Matchid == matchID {
if matchDetails.GetMatches()[0].GetMatchid() == matchID {
return matchDetails, nil
}
dml.matchRecv <- matchDetails
@@ -228,7 +243,7 @@ func (dml *DemoMatchLoader) Setup(config *DemoMatchLoaderConfig) error {
go dml.steamEventHandler()
go dml.demoWorker()
for i := 0; i < config.Worker; i++ {
for range config.Worker {
go dml.gcWorker(config.APIKey, config.RateLimit)
}
@@ -249,7 +264,7 @@ func (dml *DemoMatchLoader) LoadDemo(demo *Demo) error {
return nil
default:
dml.unlockDemo(demo)
return fmt.Errorf("queue full")
return errors.New("queue full")
}
}
@@ -273,6 +288,8 @@ func (dml *DemoMatchLoader) connectLoop() {
case LoginSuccess:
log.Info("[DL] Steam login successfully restored")
dml.connectionWait = dml.connectionWaitTmpl
default:
panic("unhandled default case")
}
}
}
@@ -285,7 +302,7 @@ func (dml *DemoMatchLoader) steamEventHandler() {
dml.client.Auth.LogOn(dml.steamLogin)
case *steam.MachineAuthUpdateEvent:
log.Debug("[DL] Got sentry!")
err := os.WriteFile(dml.sentryFile, e.Hash, os.ModePerm)
err := os.WriteFile(dml.sentryFile, e.Hash, os.ModePerm) //nolint:gosec
if err != nil {
log.Errorf("[DL] Unable write sentry file: %v", err)
}
@@ -316,7 +333,7 @@ func (dml *DemoMatchLoader) steamEventHandler() {
dml.connectFeedback <- LoginFailed
case *steam.LoginKeyEvent:
log.Debug("Got login_key!")
err := os.WriteFile(dml.loginKey, []byte(e.LoginKey), os.ModePerm)
err := os.WriteFile(dml.loginKey, []byte(e.LoginKey), os.ModePerm) //nolint:gosec
if err != nil {
log.Errorf("[DL] Unable write login_key: %v", err)
}
@@ -350,7 +367,7 @@ func (dml *DemoMatchLoader) greetGC() {
func (dml *DemoMatchLoader) requestDemoInfo(matchID, conclusionID uint64, tokenID uint32) error {
if !dml.GCReady {
return fmt.Errorf("gc not ready")
return errors.New("gc not ready")
}
msg := protobuf.CMsgGCCStrike15V2_MatchListRequestFullGameInfo{
@@ -423,7 +440,7 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit
}
matchZero := matchDetails.GetMatches()[0]
lastRound := matchZero.GetRoundstatsall()[len(matchZero.Roundstatsall)-1]
lastRound := matchZero.GetRoundstatsall()[len(matchZero.GetRoundstatsall())-1]
var players []*ent.Player //nolint:prealloc
for _, accountID := range lastRound.GetReservation().GetAccountIds() {
@@ -471,9 +488,9 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit
var oldKills int32
for _, round := range matchZero.GetRoundstatsall() {
kills, _, _, _, _, _ := playerStatsFromRound(round, mPlayer)
roundStats := playerStatsFromRound(round, mPlayer)
switch kills - oldKills {
switch roundStats.Kills - oldKills {
case 2:
mk2++
case 3:
@@ -483,20 +500,20 @@ func (dml *DemoMatchLoader) handleDemo(demo *Demo, apiKey string, rl *rate.Limit
case 5:
mk5++
}
oldKills = kills
oldKills = roundStats.Kills
}
kills, deaths, assists, hs, score, mvp := playerStatsFromRound(lastRound, mPlayer)
roundStats := playerStatsFromRound(lastRound, mPlayer)
err = tx.MatchPlayer.Create().
SetMatches(tMatch).
SetPlayers(mPlayer).
SetTeamID(teamID).
SetKills(int(kills)).
SetDeaths(int(deaths)).
SetAssists(int(assists)).
SetMvp(uint(mvp)).
SetScore(int(score)).
SetHeadshot(int(hs)).
SetKills(int(roundStats.Kills)).
SetDeaths(int(roundStats.Deaths)).
SetAssists(int(roundStats.Assists)).
SetMvp(uint(roundStats.MPVs)). //nolint:gosec
SetScore(int(roundStats.Score)).
SetHeadshot(int(roundStats.Headshots)).
SetMk2(mk2).
SetMk3(mk3).
SetMk4(mk4).

View File

@@ -7,19 +7,21 @@ import (
"encoding/gob"
"errors"
"fmt"
"github.com/aclements/go-moremath/stats"
"github.com/golang/geo/r2"
"github.com/markus-wa/demoinfocs-golang/v3/pkg/demoinfocs"
"github.com/markus-wa/demoinfocs-golang/v3/pkg/demoinfocs/common"
"github.com/markus-wa/demoinfocs-golang/v3/pkg/demoinfocs/events"
log "github.com/sirupsen/logrus"
"io"
"net/http"
"strings"
"time"
"github.com/aclements/go-moremath/stats"
"github.com/golang/geo/r2"
"github.com/markus-wa/demoinfocs-golang/v5/pkg/demoinfocs"
"github.com/markus-wa/demoinfocs-golang/v5/pkg/demoinfocs/common"
"github.com/markus-wa/demoinfocs-golang/v5/pkg/demoinfocs/events"
"github.com/markus-wa/demoinfocs-golang/v5/pkg/demoinfocs/msg"
log "github.com/sirupsen/logrus"
"somegit.dev/csgowtf/csgowtfd/ent"
"somegit.dev/csgowtf/csgowtfd/ent/matchplayer"
"somegit.dev/csgowtf/csgowtfd/utils"
"strings"
"time"
)
type Demo struct {
@@ -112,7 +114,7 @@ func (dp *DemoParser) Setup(db *ent.Client, worker, sprayTimeout int) error {
dp.db = db
dp.sprayTimeout = sprayTimeout
dp.Done = make(chan *Demo, worker)
for i := 0; i < worker; i++ {
for range worker {
go dp.parseWorker()
}
return nil
@@ -123,14 +125,14 @@ func (dp *DemoParser) ParseDemo(demo *Demo) error {
case dp.demoQueue <- demo:
return nil
default:
return fmt.Errorf("queue full")
return errors.New("queue full")
}
}
func (d *Demo) download() (io.Reader, error) {
log.Debugf("[DP] Downloading replay for %d", d.MatchID)
r, err := http.Get(d.URL) //nolint:bodyclose,noctx
r, err := http.Get(d.URL) //nolint:bodyclose
if err != nil {
return nil, err
}
@@ -152,7 +154,7 @@ func (dp *DemoParser) MatchPlayerBySteamID(mStats []*ent.MatchPlayer, steamID ui
}
}
return nil, fmt.Errorf("player not found")
return nil, errors.New("player not found")
}
func setMatchPlayerColor(matchPlayer *ent.MatchPlayer, demoPlayer *common.Player) {
@@ -255,9 +257,6 @@ workloop:
pingMap := make(map[uint64][]float64)
cfg := demoinfocs.DefaultParserConfig
if len(demo.DecryptionKey) == 16 { //nolint:gomnd
cfg.NetMessageDecryptionKey = demo.DecryptionKey
}
demoParser := demoinfocs.NewParserWithConfig(fDemo, cfg)
// onChatMessage
@@ -327,9 +326,9 @@ workloop:
return
}
if e.Attacker.Team == e.Player.Team {
tAttacker.DmgTeam += uint(e.HealthDamageTaken)
tAttacker.DmgTeam += uint(e.HealthDamageTaken) //nolint:gosec
} else {
tAttacker.DmgEnemy += uint(e.HealthDamageTaken)
tAttacker.DmgEnemy += uint(e.HealthDamageTaken) //nolint:gosec
}
if _, ok := eqMap[e.Attacker.SteamID64]; !ok {
@@ -344,7 +343,7 @@ workloop:
found := false
for _, di := range eqMap[e.Attacker.SteamID64] {
if di.Eq == int(e.Weapon.Type) && di.HitGroup == int(e.HitGroup) {
di.Dmg += uint(e.HealthDamageTaken)
di.Dmg += uint(e.HealthDamageTaken) //nolint:gosec
found = true
}
}
@@ -355,12 +354,12 @@ workloop:
HitGroup int
Dmg uint
To uint64
}{Eq: int(e.Weapon.Type), HitGroup: int(e.HitGroup), Dmg: uint(e.HealthDamageTaken), To: e.Player.SteamID64})
}{Eq: int(e.Weapon.Type), HitGroup: int(e.HitGroup), Dmg: uint(e.HealthDamageTaken), To: e.Player.SteamID64}) //nolint:gosec
}
})
// onRoundEnd
demoParser.RegisterEventHandler(func(e events.RoundEnd) {
demoParser.RegisterEventHandler(func(_ events.RoundEnd) {
gs := demoParser.GameState()
if !gs.IsMatchStarted() {
return
@@ -423,7 +422,7 @@ workloop:
})
// onMatchStart
demoParser.RegisterEventHandler(func(e events.MatchStart) {
demoParser.RegisterEventHandler(func(_ events.MatchStart) {
gs := demoParser.GameState()
for _, demoPlayer := range gs.Participants().Playing() {
@@ -460,8 +459,13 @@ workloop:
continue
}
var mapName string
demoParser.RegisterNetMessageHandler(func(m *msg.CDemoFileHeader) {
mapName = m.GetMapName()
})
err = tMatch.Update().
SetMap(demoParser.Header().MapName).
SetMap(mapName).
SetDemoParsed(true).
SetTickRate(demoParser.TickRate()).
Exec(context.Background())
@@ -526,10 +530,10 @@ workloop:
for _, eco := range ecoMap[tMatchPlayer.PlayerStats] {
err := tx.RoundStats.Create().
SetMatchPlayer(nMatchPLayer).
SetRound(uint(eco.Round)).
SetBank(uint(eco.Bank)).
SetEquipment(uint(eco.EqV)).
SetSpent(uint(eco.Spent)).
SetRound(uint(eco.Round)). //nolint:gosec
SetBank(uint(eco.Bank)). //nolint:gosec
SetEquipment(uint(eco.EqV)). //nolint:gosec
SetSpent(uint(eco.Spent)). //nolint:gosec
Exec(context.Background())
if err != nil {
err = utils.Rollback(tx, err)

View File

@@ -2,6 +2,7 @@ package csgo
import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"regexp"
@@ -29,10 +30,10 @@ func DecodeSharecode(code string) (matchID, outcomeID uint64, tokenID uint16, er
bigInt.Add(bigInt, big.NewInt(int64(strings.Index(Base57Chars, c))))
}
if bigInt.BitLen() > 144 { //nolint:gomnd
return 0, 0, 0, fmt.Errorf("invalid sharecode")
if bigInt.BitLen() > 144 {
return 0, 0, 0, errors.New("invalid sharecode")
}
bytes := make([]byte, 18) //nolint:gomnd
bytes := make([]byte, 18)
bigInt.FillBytes(bytes)
matchID = binary.LittleEndian.Uint64(bytes[0:8])

View File

@@ -1,41 +1,45 @@
package csgo
package csgo_test
import "testing"
import (
"testing"
func TestGoodSharecodes(t *testing.T) {
eMatchId := uint64(3505575050994516382)
eOutcomeId := uint64(3505581094013501947)
eTokenId := uint16(12909)
"somegit.dev/csgowtf/csgowtfd/csgo"
)
matchId, outcomeId, tokenId, err := DecodeSharecode("CSGO-P9k3F-eVL9n-LZLXN-DrBGF-VKD7K")
func TestGoodSharecodes(t *testing.T) { //nolint:paralleltest
eMatchID := uint64(3505575050994516382)
eOutcomeID := uint64(3505581094013501947)
eTokenID := uint16(12909)
matchID, outcomeId, tokenId, err := csgo.DecodeSharecode("CSGO-P9k3F-eVL9n-LZLXN-DrBGF-VKD7K")
if err != nil {
t.Log("error should be nil", err)
t.Fail()
}
if matchId != eMatchId {
t.Logf("matchID should be %d, is %d", eMatchId, matchId)
if matchID != eMatchID {
t.Logf("matchID should be %d, is %d", eMatchID, matchID)
t.Fail()
}
if outcomeId != eOutcomeId {
t.Logf("outcomeID should be %d, is %d", eOutcomeId, outcomeId)
if outcomeId != eOutcomeID {
t.Logf("outcomeID should be %d, is %d", eOutcomeID, outcomeId)
t.Fail()
}
if tokenId != eTokenId {
t.Logf("tokenID should be %d, is %d", eTokenId, tokenId)
if tokenId != eTokenID {
t.Logf("tokenID should be %d, is %d", eTokenID, tokenId)
t.Fail()
}
}
func TestBadSharecodes(t *testing.T) {
matchId, outcomeId, tokenId, err := DecodeSharecode("CSGO-AAAAA-AAAAA-AAAAA-AAAAA-AAAAA")
matchID, outcomeId, tokenId, err := csgo.DecodeSharecode("CSGO-AAAAA-AAAAA-AAAAA-AAAAA-AAAAA")
if err != nil {
t.Log("error should not be set", err)
t.Fail()
}
if matchId != 0 {
t.Logf("matchID should be 0, is %d", matchId)
if matchID != 0 {
t.Logf("matchID should be 0, is %d", matchID)
t.Fail()
}
if outcomeId != 0 {
@@ -47,14 +51,14 @@ func TestBadSharecodes(t *testing.T) {
t.Fail()
}
matchId, outcomeId, tokenId, err = DecodeSharecode("CSGO-99999-99999-99999-99999-99999")
matchID, outcomeId, tokenId, err = csgo.DecodeSharecode("CSGO-99999-99999-99999-99999-99999")
if err == nil {
t.Log("error should be set", err)
t.Fail()
}
if matchId != 0 {
t.Logf("matchID should be 0, is %d", matchId)
if matchID != 0 {
t.Logf("matchID should be 0, is %d", matchID)
t.Fail()
}
if outcomeId != 0 {