Skip to content

Commit c21afef

Browse files
committed
GameState refactoring
Moved game-state related information into GameState struct (#16)
1 parent 002958f commit c21afef

File tree

12 files changed

+508
-482
lines changed

12 files changed

+508
-482
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ func main() {
5656
p.RegisterEventHandler(func(e events.RoundEndedEvent) {
5757
switch e.Winner {
5858
case common.TeamTerrorists:
59-
fmt.Println("T-side won the round - score:", p.TState().Score()+1) // Score + 1 because it hasn't actually been updated yet
59+
fmt.Println("T-side won the round - score:", p.GameState().TState().Score()+1) // Score + 1 because it hasn't actually been updated yet
6060
case common.TeamCounterTerrorists:
61-
fmt.Println("CT-side won the round - score:", p.CTState().Score()+1)
61+
fmt.Println("CT-side won the round - score:", p.GameState().CTState().Score()+1)
6262
default:
6363
fmt.Println("Apparently neither the Ts nor CTs won the round, interesting")
6464
}

common/structs.go

Lines changed: 11 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
11
package common
22

33
import (
4-
"encoding/binary"
5-
"io"
6-
74
r3 "github.com/golang/geo/r3"
85

9-
bit "github.com/markus-wa/demoinfocs-golang/bitread"
106
st "github.com/markus-wa/demoinfocs-golang/sendtables"
117
)
128

@@ -25,26 +21,16 @@ type DemoHeader struct {
2521
SignonLength int
2622
}
2723

28-
// PlayerInfo contains general player information
29-
type PlayerInfo struct {
30-
Version int64
31-
XUID int64
32-
Name string
33-
UserID int
34-
GUID string
35-
FriendsID int
36-
FriendsName string
37-
// Custom files stuff (CRC)
38-
CustomFiles0 int
39-
CustomFiles1 int
40-
CustomFiles2 int
41-
CustomFiles3 int
42-
// Amount of downloaded files from the server
43-
FilesDownloaded byte
44-
// Bots
45-
IsFakePlayer bool
46-
// HLTV Proxy
47-
IsHltv bool
24+
// FrameRate returns the frame rate of the demo (frames / demo-ticks per second).
25+
// Not necessarily the tick-rate the server ran on during the game.
26+
// VolvoPlx128TixKTnxBye
27+
func (h DemoHeader) FrameRate() float32 {
28+
return float32(h.PlaybackFrames) / h.PlaybackTime
29+
}
30+
31+
// FrameTime returns the time a frame / demo-tick takes in seconds.
32+
func (h DemoHeader) FrameTime() float32 {
33+
return h.PlaybackTime / float32(h.PlaybackFrames)
4834
}
4935

5036
// Player contains mostly game-relevant player information.
@@ -77,6 +63,7 @@ type Player struct {
7763
IsDisconnected bool
7864
HasDefuseKit bool
7965
HasHelmet bool
66+
Connected bool
8067
}
8168

8269
// IsAlive returns true if the Hp of the player are > 0.
@@ -136,32 +123,6 @@ func NewSkinEquipment(eqName string, skinID string) Equipment {
136123
return Equipment{Weapon: wep, SkinID: skinID}
137124
}
138125

139-
// ParsePlayerInfo parses player information from a byte stream.
140-
func ParsePlayerInfo(reader io.Reader) *PlayerInfo {
141-
br := bit.NewSmallBitReader(reader)
142-
res := &PlayerInfo{
143-
Version: int64(binary.BigEndian.Uint64(br.ReadBytes(8))),
144-
XUID: int64(binary.BigEndian.Uint64(br.ReadBytes(8))),
145-
Name: br.ReadCString(128),
146-
UserID: int(int32(binary.BigEndian.Uint32(br.ReadBytes(4)))),
147-
GUID: br.ReadCString(33),
148-
FriendsID: int(int32(binary.BigEndian.Uint32(br.ReadBytes(4)))),
149-
FriendsName: br.ReadCString(128),
150-
151-
IsFakePlayer: br.ReadSingleByte()&0xff != 0,
152-
IsHltv: br.ReadSingleByte()&0xff != 0,
153-
154-
CustomFiles0: int(br.ReadInt(32)),
155-
CustomFiles1: int(br.ReadInt(32)),
156-
CustomFiles2: int(br.ReadInt(32)),
157-
CustomFiles3: int(br.ReadInt(32)),
158-
159-
FilesDownloaded: br.ReadSingleByte(),
160-
}
161-
br.Pool()
162-
return res
163-
}
164-
165126
// NewPlayer creates a *Player with an initialized equipment map.
166127
func NewPlayer() *Player {
167128
return &Player{RawWeapons: make(map[int]*Equipment)}

constants.go

Lines changed: 0 additions & 33 deletions
This file was deleted.

datatables.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ import (
88
st "github.com/markus-wa/demoinfocs-golang/sendtables"
99
)
1010

11+
const (
12+
maxEditctBits = 11
13+
indexMask = ((1 << maxEditctBits) - 1)
14+
maxEntities = (1 << maxEditctBits)
15+
maxPlayers = 64
16+
maxWeapons = 64
17+
)
18+
1119
// Everything here feels kinda fucked
1220

1321
func (p *Parser) mapEquipment() {
@@ -77,11 +85,11 @@ func (p *Parser) bindTeamScores() {
7785

7886
switch team {
7987
case "CT":
80-
s = &p.ctState
88+
s = &p.gameState.ctState
8189
t = common.TeamCounterTerrorists
8290

8391
case "TERRORIST":
84-
s = &p.tState
92+
s = &p.gameState.tState
8593
t = common.TeamTerrorists
8694

8795
case "Unassigned": // Ignore
@@ -113,7 +121,7 @@ func (p *Parser) bindTeamScores() {
113121
// FIXME: This only sets the team at the start. . . We also have a player-specific update handler that changes the team so maybe this is unnecessary?
114122
if teamID != -1 {
115123
s.id = teamID
116-
for _, pl := range p.players {
124+
for _, pl := range p.entityIDToPlayers {
117125
if pl != nil && pl.TeamID == teamID {
118126
pl.Team = t
119127
}
@@ -180,11 +188,12 @@ func (p *Parser) bindPlayers() {
180188

181189
func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
182190
var pl *common.Player
183-
if p.players[playerEntity.ID-1] != nil {
184-
pl = p.players[playerEntity.ID-1]
191+
playerIndex := playerEntity.ID - 1
192+
if p.entityIDToPlayers[playerIndex] != nil {
193+
pl = p.entityIDToPlayers[playerIndex]
185194
} else {
186195
pl = common.NewPlayer()
187-
p.players[playerEntity.ID-1] = pl
196+
p.entityIDToPlayers[playerIndex] = pl
188197
pl.SteamID = -1
189198
pl.Name = "unconnected"
190199
}
@@ -206,9 +215,9 @@ func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
206215

207216
// FIXME: We could probably just cast TeamID to common.Team or not even set it because the teamIDs should be the same. . . needs testing
208217
switch pl.TeamID {
209-
case p.ctState.id:
218+
case p.gameState.ctState.id:
210219
pl.Team = common.TeamCounterTerrorists
211-
case p.tState.id:
220+
case p.gameState.tState.id:
212221
pl.Team = common.TeamTerrorists
213222
default:
214223
pl.Team = common.TeamSpectators

demoinfocs_test.go

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,27 +36,27 @@ func TestDemoInfoCs(t *testing.T) {
3636
p := dem.NewParser(f, dem.WarnToStdErr)
3737

3838
fmt.Println("Parsing header")
39-
p.RegisterEventHandler(func(e events.HeaderParsedEvent) {
40-
fmt.Printf("Header: %v\n", e)
41-
})
42-
p.ParseHeader()
39+
h, err := p.ParseHeader()
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
fmt.Printf("Header: %v\n", h)
4344

4445
fmt.Println("Registering handlers")
45-
var tState *dem.TeamState
46-
var ctState *dem.TeamState
47-
var oldTScore int
48-
var oldCtScore int
46+
tState := p.GameState().TState()
47+
ctState := p.GameState().CTState()
48+
var oldTScore, oldCtScore int
4949
p.RegisterEventHandler(func(events.TickDoneEvent) {
50-
if tState != nil && oldTScore != tState.Score() {
51-
fmt.Println("T-side score:", tState.Score())
52-
oldTScore = tState.Score()
53-
} else if ctState != nil && oldCtScore != ctState.Score() {
54-
fmt.Println("CT-side score:", ctState.Score())
55-
oldCtScore = ctState.Score()
50+
newTScore := tState.Score()
51+
newCtScore := ctState.Score()
52+
if oldTScore != newTScore {
53+
fmt.Println("T-side score:", newTScore)
54+
oldTScore = newTScore
55+
} else if ctState != nil && oldCtScore != newCtScore {
56+
fmt.Println("CT-side score:", newCtScore)
57+
oldCtScore = newCtScore
5658
}
5759
})
58-
tState = p.TState()
59-
ctState = p.CTState()
6060

6161
ts := time.Now()
6262
var done int64

entities.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package demoinfocs
2+
3+
import (
4+
"bytes"
5+
6+
bit "github.com/markus-wa/demoinfocs-golang/bitread"
7+
msg "github.com/markus-wa/demoinfocs-golang/msg"
8+
st "github.com/markus-wa/demoinfocs-golang/sendtables"
9+
)
10+
11+
const entitySentinel = 9999
12+
13+
func (p *Parser) handlePacketEntities(pe *msg.CSVCMsg_PacketEntities) {
14+
defer func() {
15+
p.setError(recoverFromUnexpectedEOF(recover()))
16+
}()
17+
18+
r := bit.NewSmallBitReader(bytes.NewReader(pe.EntityData))
19+
20+
currentEntity := -1
21+
for i := 0; i < int(pe.UpdatedEntries); i++ {
22+
currentEntity += 1 + int(r.ReadUBitInt())
23+
24+
if currentEntity > entitySentinel {
25+
break
26+
}
27+
28+
if r.ReadBit() {
29+
// Leave PVS
30+
31+
// FIXME: Might have to destroy the entities contents first, not sure yet
32+
// Could do weird stuff with event handlers otherwise
33+
p.entities[currentEntity] = nil
34+
35+
if r.ReadBit() {
36+
// TODO: Force Delete??
37+
}
38+
} else {
39+
if r.ReadBit() {
40+
// Enter PVS
41+
e := p.readEnterPVS(r, currentEntity)
42+
p.entities[currentEntity] = e
43+
e.ApplyUpdate(r)
44+
} else {
45+
// Delta Update
46+
p.entities[currentEntity].ApplyUpdate(r)
47+
}
48+
}
49+
}
50+
r.Pool()
51+
}
52+
53+
func (p *Parser) readEnterPVS(reader *bit.BitReader, entityID int) *st.Entity {
54+
scID := int(reader.ReadInt(p.stParser.ClassBits()))
55+
reader.Skip(10) // Serial Number
56+
57+
newEntity := st.NewEntity(entityID, p.stParser.ServerClasses()[scID])
58+
newEntity.ServerClass.FireEntityCreatedEvent(newEntity)
59+
60+
if p.preprocessedBaselines[scID] != nil {
61+
for idx, val := range p.preprocessedBaselines[scID] {
62+
newEntity.Props()[idx].FirePropertyUpdate(val)
63+
}
64+
} else {
65+
ppBase := make(map[int]st.PropValue, 0)
66+
if p.instanceBaselines[scID] != nil {
67+
newEntity.CollectProperties(&ppBase)
68+
r := bit.NewSmallBitReader(bytes.NewReader(p.instanceBaselines[scID]))
69+
newEntity.ApplyUpdate(r)
70+
r.Pool()
71+
// TODO: Unregister PropertyUpdateHandlers from CollectProperties()
72+
// PropertyUpdateHandlers would have to be registered as pointers for that to work
73+
}
74+
p.preprocessedBaselines[scID] = ppBase
75+
}
76+
77+
return newEntity
78+
}

example_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ func TestExample(t *testing.T) {
3131
p.RegisterEventHandler(func(e events.RoundEndedEvent) {
3232
switch e.Winner {
3333
case common.TeamTerrorists:
34-
fmt.Println("T-side won the round - score:", p.TState().Score()+1) // Score + 1 because it hasn't actually been updated yet
34+
fmt.Println("T-side won the round - score:", p.GameState().TState().Score()+1) // Score + 1 because it hasn't actually been updated yet
3535
case common.TeamCounterTerrorists:
36-
fmt.Println("CT-side won the round - score:", p.CTState().Score()+1)
36+
fmt.Println("CT-side won the round - score:", p.GameState().CTState().Score()+1)
3737
default:
3838
fmt.Println("Apparently neither the Ts nor CTs won the round, interesting")
3939
}

0 commit comments

Comments
 (0)