Skip to content

Commit 4e49452

Browse files
committed
common: replaced AdditionalPlayerInformation with CCSPlayerResource entity
1 parent 196fba8 commit 4e49452

File tree

6 files changed

+100
-63
lines changed

6 files changed

+100
-63
lines changed

pkg/demoinfocs/common/common.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ func (ts TeamState) FreezeTimeEndEquipmentValue() (value int) {
183183
// MoneySpentThisRound returns the total amount of cash spent by the whole team in the current round.
184184
func (ts TeamState) MoneySpentThisRound() (value int) {
185185
for _, pl := range ts.Members() {
186-
value += pl.AdditionalInformation.MoneySpentThisRound
186+
value += pl.MoneySpentThisRound()
187187
}
188188

189189
return
@@ -192,7 +192,7 @@ func (ts TeamState) MoneySpentThisRound() (value int) {
192192
// MoneySpentThisRound returns the total amount of cash spent by the whole team during the whole game up to the current point.
193193
func (ts TeamState) MoneySpentTotal() (value int) {
194194
for _, pl := range ts.Members() {
195-
value += pl.AdditionalInformation.MoneySpentTotal
195+
value += pl.MoneySpentTotal()
196196
}
197197

198198
return

pkg/demoinfocs/common/common_test.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ func TestTeamState_EquipmentValueFreezeTimeEnd(t *testing.T) {
9595

9696
func TestTeamState_MoneySpentThisRound(t *testing.T) {
9797
members := []*Player{
98-
{AdditionalInformation: &AdditionalPlayerInformation{MoneySpentThisRound: 100}},
99-
{AdditionalInformation: &AdditionalPlayerInformation{MoneySpentThisRound: 200}},
98+
NewPlayer(demoInfoProviderMock{playerResourceEntity: entityWithProperty("m_iCashSpentThisRound.000", st.PropertyValue{IntVal: 100})}),
99+
NewPlayer(demoInfoProviderMock{playerResourceEntity: entityWithProperty("m_iCashSpentThisRound.000", st.PropertyValue{IntVal: 200})}),
100100
}
101101
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
102102

@@ -105,18 +105,19 @@ func TestTeamState_MoneySpentThisRound(t *testing.T) {
105105

106106
func TestTeamState_MoneySpentTotal(t *testing.T) {
107107
members := []*Player{
108-
{AdditionalInformation: &AdditionalPlayerInformation{MoneySpentTotal: 100}},
109-
{AdditionalInformation: &AdditionalPlayerInformation{MoneySpentTotal: 200}},
108+
NewPlayer(demoInfoProviderMock{playerResourceEntity: entityWithProperty("m_iTotalCashSpent.000", st.PropertyValue{IntVal: 100})}),
109+
NewPlayer(demoInfoProviderMock{playerResourceEntity: entityWithProperty("m_iTotalCashSpent.000", st.PropertyValue{IntVal: 200})}),
110110
}
111111
state := NewTeamState(TeamTerrorists, func(Team) []*Player { return members })
112112

113113
assert.Equal(t, 300, state.MoneySpentTotal())
114114
}
115115

116116
type demoInfoProviderMock struct {
117-
tickRate float64
118-
ingameTick int
119-
playersByHandle map[int]*Player
117+
tickRate float64
118+
ingameTick int
119+
playersByHandle map[int]*Player
120+
playerResourceEntity st.IEntity
120121
}
121122

122123
func (p demoInfoProviderMock) TickRate() float64 {
@@ -131,6 +132,10 @@ func (p demoInfoProviderMock) FindPlayerByHandle(handle int) *Player {
131132
return p.playersByHandle[handle]
132133
}
133134

135+
func (p demoInfoProviderMock) PlayerResourceEntity() st.IEntity {
136+
return p.playerResourceEntity
137+
}
138+
134139
func mockDemoInfoProvider(tickRate float64, tick int) demoInfoProvider {
135140
return demoInfoProviderMock{
136141
tickRate: tickRate,

pkg/demoinfocs/common/player.go

Lines changed: 74 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package common
22

33
import (
4+
"fmt"
45
"time"
56

67
"github.com/golang/geo/r3"
@@ -20,25 +21,24 @@ const (
2021
type Player struct {
2122
demoInfoProvider demoInfoProvider // provider for demo info such as tick-rate or current tick
2223

23-
SteamID int64 // int64 representation of the User's Steam ID
24-
LastAlivePosition r3.Vector // The location where the player was last alive. Should be equal to Position if the player is still alive.
25-
UserID int // Mostly used in game-events to address this player
26-
Name string // Steam / in-game user name
27-
Inventory map[int]*Equipment // All weapons / equipment the player is currently carrying
28-
AmmoLeft [32]int // Ammo left for special weapons (e.g. grenades), index corresponds Equipment.AmmoType
29-
EntityID int // Usually the same as Entity.ID() but may be different between player death and re-spawn.
30-
Entity st.IEntity // May be nil between player-death and re-spawn
31-
AdditionalInformation *AdditionalPlayerInformation // Mostly scoreboard information such as kills, deaths, etc.
32-
FlashDuration float32 // Blindness duration from the flashbang currently affecting the player (seconds)
33-
FlashTick int // In-game tick at which the player was last flashed
34-
TeamState *TeamState // When keeping the reference make sure you notice when the player changes teams
35-
Team Team // Team identifier for the player (e.g. TeamTerrorists or TeamCounterTerrorists).
36-
IsBot bool // True if this is a bot-entity. See also IsControllingBot and ControlledBot().
37-
IsConnected bool
38-
IsDefusing bool
39-
IsPlanting bool
40-
IsReloading bool
41-
IsUnknown bool // Used to identify unknown/broken players. see https://github.com/markus-wa/demoinfocs-golang/issues/162
24+
SteamID int64 // int64 representation of the User's Steam ID
25+
LastAlivePosition r3.Vector // The location where the player was last alive. Should be equal to Position if the player is still alive.
26+
UserID int // Mostly used in game-events to address this player
27+
Name string // Steam / in-game user name
28+
Inventory map[int]*Equipment // All weapons / equipment the player is currently carrying
29+
AmmoLeft [32]int // Ammo left for special weapons (e.g. grenades), index corresponds Equipment.AmmoType
30+
EntityID int // Usually the same as Entity.ID() but may be different between player death and re-spawn.
31+
Entity st.IEntity // May be nil between player-death and re-spawn
32+
FlashDuration float32 // Blindness duration from the flashbang currently affecting the player (seconds)
33+
FlashTick int // In-game tick at which the player was last flashed
34+
TeamState *TeamState // When keeping the reference make sure you notice when the player changes teams
35+
Team Team // Team identifier for the player (e.g. TeamTerrorists or TeamCounterTerrorists).
36+
IsBot bool // True if this is a bot-entity. See also IsControllingBot and ControlledBot().
37+
IsConnected bool
38+
IsDefusing bool
39+
IsPlanting bool
40+
IsReloading bool
41+
IsUnknown bool // Used to identify unknown/broken players. see https://github.com/markus-wa/demoinfocs-golang/issues/162
4242
}
4343

4444
// String returns the player's name.
@@ -121,6 +121,11 @@ Going by the last two lines, the player should not have been blinded at ~49m57.0
121121
This isn't very conclusive but it looks like IsFlashed isn't super reliable currently.
122122
*/
123123

124+
// Used internally to set the active weapon, see ActiveWeapon()
125+
func (p *Player) activeWeaponID() int {
126+
return getInt(p.Entity, "m_hActiveWeapon") & entityHandleIndexMask
127+
}
128+
124129
// ActiveWeapon returns the currently active / equipped weapon of the player.
125130
func (p *Player) ActiveWeapon() *Equipment {
126131
return p.Inventory[p.activeWeaponID()]
@@ -280,28 +285,64 @@ func (p *Player) Velocity() r3.Vector {
280285
}
281286
}
282287

283-
// Used internally to set the active weapon, see ActiveWeapon()
284-
func (p *Player) activeWeaponID() int {
285-
return getInt(p.Entity, "m_hActiveWeapon") & entityHandleIndexMask
288+
/////////////////////////////
289+
// CCSPlayerResource stuff //
290+
/////////////////////////////
291+
292+
func (p *Player) entityIDStr() string {
293+
return fmt.Sprintf("%03d", p.EntityID)
294+
}
295+
296+
// ClanTag returns the player's individual clan tag (Steam Groups etc.).
297+
func (p *Player) ClanTag() string {
298+
return getString(p.demoInfoProvider.PlayerResourceEntity(), "m_szClan."+p.entityIDStr())
299+
}
300+
301+
// Ping returns the players latency to the game server.
302+
func (p *Player) Ping() int {
303+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iPing."+p.entityIDStr())
304+
}
305+
306+
// Score returns the players score as shown on the scoreboard.
307+
func (p *Player) Score() int {
308+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iScore."+p.entityIDStr())
309+
}
310+
311+
// Kills returns the amount of kills the player has as shown on the scoreboard.
312+
func (p *Player) Kills() int {
313+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iKills."+p.entityIDStr())
314+
}
315+
316+
// Deaths returns the amount of deaths the player has as shown on the scoreboard.
317+
func (p *Player) Deaths() int {
318+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iDeaths."+p.entityIDStr())
319+
}
320+
321+
// Assists returns the amount of assists the player has as shown on the scoreboard.
322+
func (p *Player) Assists() int {
323+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iAssists."+p.entityIDStr())
324+
}
325+
326+
// MVPs returns the amount of Most-Valuable-Player awards the player has as shown on the scoreboard.
327+
func (p *Player) MVPs() int {
328+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iMVPs."+p.entityIDStr())
329+
}
330+
331+
// MoneySpentTotal returns the total amount of money the player has spent in the current match.
332+
func (p *Player) MoneySpentTotal() int {
333+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iTotalCashSpent."+p.entityIDStr())
286334
}
287335

288-
// AdditionalPlayerInformation contains mostly scoreboard information.
289-
type AdditionalPlayerInformation struct {
290-
Kills int
291-
Deaths int
292-
Assists int
293-
Score int
294-
MVPs int
295-
Ping int
296-
ClanTag string
297-
MoneySpentTotal int
298-
MoneySpentThisRound int
336+
// MoneySpentThisRound returns the amount of money the player has spent in the current round.
337+
func (p *Player) MoneySpentThisRound() int {
338+
return getInt(p.demoInfoProvider.PlayerResourceEntity(), "m_iCashSpentThisRound."+p.entityIDStr())
299339
}
300340

301341
type demoInfoProvider interface {
302342
IngameTick() int // current in-game tick, used for IsBlinded()
303343
TickRate() float64 // in-game tick rate, used for Player.IsBlinded()
304344
FindPlayerByHandle(handle int) *Player
345+
PlayerResourceEntity() st.IEntity
305346
}
306347

307348
// NewPlayer creates a *Player with an initialized equipment map.

pkg/demoinfocs/datatables.go

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -174,23 +174,8 @@ func (p *Parser) bindPlayers() {
174174
p.bindNewPlayer(player)
175175
})
176176

177-
p.stParser.ServerClasses().FindByName("CCSPlayerResource").OnEntityCreated(func(plInfo *st.Entity) {
178-
for i := 0; i < maxPlayers; i++ {
179-
i2 := i // Copy so it stays the same (for passing to handlers)
180-
iStr := fmt.Sprintf("%03d", i)
181-
182-
plInfo.BindProperty("m_szClan."+iStr, &p.additionalPlayerInfo[i2].ClanTag, st.ValTypeString)
183-
plInfo.BindProperty("m_iPing."+iStr, &p.additionalPlayerInfo[i2].Ping, st.ValTypeInt)
184-
plInfo.BindProperty("m_iScore."+iStr, &p.additionalPlayerInfo[i2].Score, st.ValTypeInt)
185-
plInfo.BindProperty("m_iKills."+iStr, &p.additionalPlayerInfo[i2].Kills, st.ValTypeInt)
186-
plInfo.BindProperty("m_iDeaths."+iStr, &p.additionalPlayerInfo[i2].Deaths, st.ValTypeInt)
187-
plInfo.BindProperty("m_iAssists."+iStr, &p.additionalPlayerInfo[i2].Assists, st.ValTypeInt)
188-
plInfo.BindProperty("m_iMVPs."+iStr, &p.additionalPlayerInfo[i2].MVPs, st.ValTypeInt)
189-
plInfo.BindProperty("m_iTotalCashSpent."+iStr, &p.additionalPlayerInfo[i2].MoneySpentTotal, st.ValTypeInt)
190-
if prop := plInfo.Property("m_iCashSpentThisRound." + iStr); prop != nil {
191-
prop.Bind(&p.additionalPlayerInfo[i2].MoneySpentThisRound, st.ValTypeInt)
192-
}
193-
}
177+
p.stParser.ServerClasses().FindByName("CCSPlayerResource").OnEntityCreated(func(entity *st.Entity) {
178+
p.playerResourceEntity = entity
194179
})
195180
}
196181

@@ -238,7 +223,6 @@ func (p *Parser) bindNewPlayer(playerEntity st.IEntity) {
238223

239224
pl.EntityID = entityID
240225
pl.Entity = playerEntity
241-
pl.AdditionalInformation = &p.additionalPlayerInfo[entityID]
242226
pl.IsConnected = true
243227

244228
playerEntity.OnDestroy(func() {

pkg/demoinfocs/events/events_test.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"github.com/stretchr/testify/assert"
88

99
common "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/common"
10-
"github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables"
10+
st "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables"
1111
stfake "github.com/markus-wa/demoinfocs-golang/v2/pkg/demoinfocs/sendtables/fake"
1212
)
1313

@@ -68,7 +68,7 @@ func TestItemPickup_WeaponTraceable_WeaponFound(t *testing.T) {
6868
assert.Equal(t, wep, e.WeaponTraceable())
6969
}
7070

71-
func entity() sendtables.IEntity {
71+
func entity() st.IEntity {
7272
entity := new(stfake.Entity)
7373
entity.On("ID").Return(1)
7474

@@ -104,3 +104,6 @@ func (p demoInfoProviderMock) TickRate() float64 {
104104
func (p demoInfoProviderMock) FindPlayerByHandle(handle int) *common.Player {
105105
return nil
106106
}
107+
func (p demoInfoProviderMock) PlayerResourceEntity() st.IEntity {
108+
return nil
109+
}

pkg/demoinfocs/parser.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,13 @@ type Parser struct {
6666
bombsiteB bombsite
6767
equipmentMapping map[*st.ServerClass]common.EquipmentType // Maps server classes to equipment-types
6868
rawPlayers map[int]*playerInfo // Maps entity IDs to 'raw' player info
69-
additionalPlayerInfo [maxPlayers]common.AdditionalPlayerInformation // Maps entity IDs to additional player info (scoreboard info)
7069
modelPreCache []string // Used to find out whether a weapon is a p250 or cz for example (same id)
7170
triggers map[int]*boundingBoxInformation // Maps entity IDs to triggers (used for bombsites)
7271
gameEventDescs map[int32]*msg.CSVCMsg_GameEventListDescriptorT // Maps game-event IDs to descriptors
7372
grenadeModelIndices map[int]common.EquipmentType // Used to map model indices to grenades (used for grenade projectiles)
7473
stringTables []*msg.CSVCMsg_CreateStringTable // Contains all created sendtables, needed when updating them
7574
delayedEventHandlers []func() // Contains event handlers that need to be executed at the end of a tick (e.g. flash events because FlashDuration isn't updated before that)
75+
playerResourceEntity st.IEntity // CCSPlayerResource entity instance, contains scoreboard info and more
7676
}
7777

7878
// NetMessageCreator creates additional net-messages to be dispatched to net-message handlers.
@@ -342,3 +342,7 @@ func (p demoInfoProvider) TickRate() float64 {
342342
func (p demoInfoProvider) FindPlayerByHandle(handle int) *common.Player {
343343
return p.parser.gameState.Participants().FindByHandle(handle)
344344
}
345+
346+
func (p demoInfoProvider) PlayerResourceEntity() st.IEntity {
347+
return p.parser.playerResourceEntity
348+
}

0 commit comments

Comments
 (0)