Skip to content

Commit baa5498

Browse files
committed
Change how players are accessed via external API
GameState.Participants() Also adds more helper functions: Participants.{All(),Playing(),TeamMembers(),ByUserID(),ByEntityID(),FindByHandle()}
1 parent 0af7d16 commit baa5498

File tree

9 files changed

+143
-88
lines changed

9 files changed

+143
-88
lines changed

common/structs.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type Player struct {
4242
LastAlivePosition r3.Vector
4343
Velocity r3.Vector
4444
EntityID int
45+
UserID int
4546
Name string
4647
Hp int
4748
Armor int

datatables.go

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,14 @@ import (
1010
)
1111

1212
const (
13-
maxEdictBits = 11
14-
indexMask = ((1 << maxEdictBits) - 1)
15-
maxEntities = (1 << maxEdictBits)
16-
maxPlayers = 64
17-
maxWeapons = 64
13+
maxEdictBits = 11
14+
entityHandleIndexMask = ((1 << maxEdictBits) - 1)
15+
entityHandleSerialNumberBits = 10
16+
entityHandleBits = maxEdictBits + entityHandleSerialNumberBits
17+
invalidEntityHandle = (1 << entityHandleBits) - 1
18+
maxEntities = (1 << maxEdictBits)
19+
maxPlayers = 64
20+
maxWeapons = 64
1821
)
1922

2023
func (p *Parser) mapEquipment() {
@@ -149,19 +152,23 @@ func (p *Parser) bindPlayers() {
149152

150153
func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
151154
var pl *common.Player
152-
playerIndex := playerEntity.ID() - 1
153-
if p.entityIDToPlayers[playerIndex] != nil {
154-
pl = p.entityIDToPlayers[playerIndex]
155+
playerIndex := playerEntity.ID()
156+
if p.gameState.playersByEntityID[playerIndex] != nil {
157+
pl = p.gameState.playersByEntityID[playerIndex]
155158
} else {
156159
pl = common.NewPlayer()
157-
p.entityIDToPlayers[playerIndex] = pl
160+
p.gameState.playersByEntityID[playerIndex] = pl
158161
pl.SteamID = -1
159162
pl.Name = "unconnected"
160163
}
161164

162165
pl.EntityID = playerEntity.ID()
163166
pl.Entity = playerEntity
164167

168+
playerEntity.OnDestroy(func() {
169+
delete(p.gameState.playersByEntityID, pl.EntityID)
170+
})
171+
165172
// Position
166173
playerEntity.FindProperty("cslocaldata.m_vecOrigin").OnUpdate(func(val st.PropertyValue) {
167174
pl.Position.X = val.VectorVal.X
@@ -207,8 +214,8 @@ func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
207214
for i := range cache {
208215
i2 := i // Copy for passing to handler
209216
playerEntity.FindProperty(wepPrefix + fmt.Sprintf("%03d", i)).OnUpdate(func(val st.PropertyValue) {
210-
entityID := val.IntVal & indexMask
211-
if entityID != indexMask {
217+
entityID := val.IntVal & entityHandleIndexMask
218+
if entityID != entityHandleIndexMask {
212219
if cache[i2] != 0 {
213220
// Player already has a weapon in this slot.
214221
delete(pl.RawWeapons, cache[i2])
@@ -232,7 +239,7 @@ func (p *Parser) bindNewPlayer(playerEntity *st.Entity) {
232239

233240
// Active weapon
234241
playerEntity.FindProperty("m_hActiveWeapon").OnUpdate(func(val st.PropertyValue) {
235-
pl.ActiveWeaponID = val.IntVal & indexMask
242+
pl.ActiveWeaponID = val.IntVal & entityHandleIndexMask
236243
})
237244

238245
for i := 0; i < 32; i++ {
@@ -278,17 +285,15 @@ func (p *Parser) bindGrenadeProjectiles(entity *st.Entity) {
278285

279286
// @micvbang: not quite sure what the difference between Thrower and Owner is.
280287
entity.FindProperty("m_hThrower").OnUpdate(func(val st.PropertyValue) {
281-
throwerID := val.IntVal & indexMask
282-
throwerIndex := throwerID - 1
288+
throwerID := val.IntVal & entityHandleIndexMask
283289

284-
thrower := p.entityIDToPlayers[throwerIndex]
290+
thrower := p.gameState.playersByEntityID[throwerID]
285291
proj.Thrower = thrower
286292
})
287293

288294
entity.FindProperty("m_hOwnerEntity").OnUpdate(func(val st.PropertyValue) {
289-
ownerID := val.IntVal & indexMask
290-
ownerIndex := ownerID - 1
291-
player := p.entityIDToPlayers[ownerIndex]
295+
ownerID := val.IntVal & entityHandleIndexMask
296+
player := p.gameState.playersByEntityID[ownerID]
292297
proj.Owner = player
293298
})
294299

demoinfocs_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,20 +101,21 @@ func TestDemoInfoCs(t *testing.T) {
101101
// Check some things at match start
102102
p.RegisterEventHandler(func(events.MatchStartedEvent) {
103103
participants := gs.Participants()
104-
players := gs.PlayingParticipants()
105-
if len(participants) <= len(players) {
104+
all := participants.All()
105+
players := participants.Playing()
106+
if len(all) <= len(players) {
106107
// We know the default demo has spectators
107108
t.Error("Expected more participants than players (spectators)")
108109
}
109110
if nPlayers := len(players); nPlayers != 10 {
110111
// We know there should be 10 players at match start in the default demo
111112
t.Error("Expected 10 players; got", nPlayers)
112113
}
113-
if nTerrorists := len(gs.TeamMembers(common.TeamTerrorists)); nTerrorists != 5 {
114+
if nTerrorists := len(participants.TeamMembers(common.TeamTerrorists)); nTerrorists != 5 {
114115
// We know there should be 5 terrorists at match start in the default demo
115116
t.Error("Expected 5 terrorists; got", nTerrorists)
116117
}
117-
if nCTs := len(gs.TeamMembers(common.TeamCounterTerrorists)); nCTs != 5 {
118+
if nCTs := len(participants.TeamMembers(common.TeamCounterTerrorists)); nCTs != 5 {
118119
// We know there should be 5 CTs at match start in the default demo
119120
t.Error("Expected 5 CTs; got", nCTs)
120121
}

game_events.go

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
3737
debugGameEvent(d, ge)
3838

3939
// Ignore events before players are connected to speed things up
40-
if len(p.gameState.players) == 0 && d.Name != "player_connect" {
40+
if len(p.gameState.playersByUserID) == 0 && d.Name != "player_connect" {
4141
return
4242
}
4343

@@ -86,14 +86,14 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
8686
data = mapGameEventData(d, ge)
8787

8888
p.eventDispatcher.Dispatch(events.RoundMVPEvent{
89-
Player: p.gameState.players[int(data["userid"].GetValShort())],
89+
Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())],
9090
Reason: events.RoundMVPReason(data["reason"].GetValShort()),
9191
})
9292

9393
case "bot_takeover": // Bot got taken over
9494
data = mapGameEventData(d, ge)
9595

96-
p.eventDispatcher.Dispatch(events.BotTakenOverEvent{Taker: p.gameState.players[int(data["userid"].GetValShort())]})
96+
p.eventDispatcher.Dispatch(events.BotTakenOverEvent{Taker: p.gameState.playersByUserID[int(data["userid"].GetValShort())]})
9797

9898
case "begin_new_match": // Match started
9999
p.eventDispatcher.Dispatch(events.MatchStartedEvent{})
@@ -105,17 +105,17 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
105105
data = mapGameEventData(d, ge)
106106

107107
p.eventDispatcher.Dispatch(events.PlayerFootstepEvent{
108-
Player: p.gameState.players[int(data["userid"].GetValShort())],
108+
Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())],
109109
})
110110

111111
case "player_jump": // Player jumped
112112
data = mapGameEventData(d, ge)
113-
p.eventDispatcher.Dispatch(events.PlayerJumpEvent{Player: p.gameState.players[int(data["userid"].GetValShort())]})
113+
p.eventDispatcher.Dispatch(events.PlayerJumpEvent{Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())]})
114114

115115
case "weapon_fire": // Weapon was fired
116116
data = mapGameEventData(d, ge)
117117

118-
shooter := p.gameState.players[int(data["userid"].GetValShort())]
118+
shooter := p.gameState.playersByUserID[int(data["userid"].GetValShort())]
119119
wep := common.NewEquipment(data["weapon"].GetValString())
120120

121121
p.eventDispatcher.Dispatch(events.WeaponFiredEvent{
@@ -126,13 +126,13 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
126126
case "player_death": // Player died
127127
data = mapGameEventData(d, ge)
128128

129-
killer := p.gameState.players[int(data["attacker"].GetValShort())]
129+
killer := p.gameState.playersByUserID[int(data["attacker"].GetValShort())]
130130
wep := common.NewSkinEquipment(data["weapon"].GetValString(), data["weapon_itemid"].GetValString())
131131

132132
p.eventDispatcher.Dispatch(events.PlayerKilledEvent{
133-
Victim: p.gameState.players[int(data["userid"].GetValShort())],
133+
Victim: p.gameState.playersByUserID[int(data["userid"].GetValShort())],
134134
Killer: killer,
135-
Assister: p.gameState.players[int(data["assister"].GetValShort())],
135+
Assister: p.gameState.playersByUserID[int(data["assister"].GetValShort())],
136136
IsHeadshot: data["headshot"].GetValBool(),
137137
PenetratedObjects: int(data["penetrated"].GetValShort()),
138138
Weapon: getAttackingWeapon(&wep, killer),
@@ -141,11 +141,11 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
141141
case "player_hurt": // Player got hurt
142142
data = mapGameEventData(d, ge)
143143

144-
attacker := p.gameState.players[int(data["attacker"].GetValShort())]
144+
attacker := p.gameState.playersByUserID[int(data["attacker"].GetValShort())]
145145
wep := common.NewEquipment(data["weapon"].GetValString())
146146

147147
p.eventDispatcher.Dispatch(events.PlayerHurtEvent{
148-
Player: p.gameState.players[int(data["userid"].GetValShort())],
148+
Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())],
149149
Attacker: attacker,
150150
Health: int(data["health"].GetValByte()),
151151
Armor: int(data["armor"].GetValByte()),
@@ -157,7 +157,7 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
157157

158158
case "player_blind": // Player got blinded by a flash
159159
data = mapGameEventData(d, ge)
160-
p.eventDispatcher.Dispatch(events.PlayerFlashedEvent{Player: p.gameState.players[int(data["userid"].GetValShort())]})
160+
p.eventDispatcher.Dispatch(events.PlayerFlashedEvent{Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())]})
161161

162162
case "flashbang_detonate": // Flash exploded
163163
fallthrough
@@ -175,7 +175,7 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
175175
fallthrough
176176
case "inferno_expire": // Incendiary expired
177177
data = mapGameEventData(d, ge)
178-
thrower := p.gameState.players[int(data["userid"].GetValShort())]
178+
thrower := p.gameState.playersByUserID[int(data["userid"].GetValShort())]
179179
position := r3.Vector{
180180
X: float64(data["x"].ValFloat),
181181
Y: float64(data["y"].ValFloat),
@@ -233,25 +233,20 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
233233
}
234234
}
235235

236-
pl := p.gameState.players[uid]
236+
pl := p.gameState.playersByUserID[uid]
237237
if pl != nil {
238238
e := events.PlayerDisconnectEvent{
239239
Player: pl,
240240
}
241241
p.eventDispatcher.Dispatch(e)
242242
}
243243

244-
delete(p.gameState.players, uid)
245-
for k, v := range p.entityIDToPlayers {
246-
if v == pl {
247-
delete(p.entityIDToPlayers, k)
248-
}
249-
}
244+
delete(p.gameState.playersByUserID, uid)
250245

251246
case "player_team": // Player changed team
252247
data = mapGameEventData(d, ge)
253248

254-
player := p.gameState.players[int(data["userid"].GetValShort())]
249+
player := p.gameState.playersByUserID[int(data["userid"].GetValShort())]
255250
newTeam := common.Team(data["team"].GetValByte())
256251

257252
if player != nil {
@@ -285,7 +280,7 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
285280
case "bomb_exploded": // Bomb exploded
286281
data = mapGameEventData(d, ge)
287282

288-
e := events.BombEvent{Player: p.gameState.players[int(data["userid"].GetValShort())]}
283+
e := events.BombEvent{Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())]}
289284

290285
site := int(data["site"].GetValShort())
291286

@@ -327,7 +322,7 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
327322
data = mapGameEventData(d, ge)
328323

329324
p.eventDispatcher.Dispatch(events.BombBeginDefuseEvent{
330-
Player: p.gameState.players[int(data["userid"].GetValShort())],
325+
Player: p.gameState.playersByUserID[int(data["userid"].GetValShort())],
331326
HasKit: data["haskit"].GetValBool(),
332327
})
333328

@@ -337,7 +332,7 @@ func (p *Parser) handleGameEvent(ge *msg.CSVCMsg_GameEvent) {
337332
fallthrough
338333
case "item_remove": // Dropped?
339334
data = mapGameEventData(d, ge)
340-
player := p.gameState.players[int(data["userid"].GetValShort())]
335+
player := p.gameState.playersByUserID[int(data["userid"].GetValShort())]
341336
weapon := common.NewSkinEquipment(data["item"].GetValString(), "")
342337

343338
switch d.Name {
@@ -505,7 +500,7 @@ func (p *Parser) handleUserMessage(um *msg.CSVCMsg_UserMessage) {
505500
p.eventDispatcher.Dispatch(events.ParserWarnEvent{Message: fmt.Sprintf("Failed to decode SayText2 message: %s", err.Error())})
506501
}
507502

508-
sender := p.gameState.players[int(st.EntIdx)]
503+
sender := p.gameState.playersByUserID[int(st.EntIdx)]
509504
p.eventDispatcher.Dispatch(events.SayText2Event{
510505
Sender: sender,
511506
IsChat: st.Chat,

0 commit comments

Comments
 (0)