Skip to content

Commit 9a30b33

Browse files
committed
S2 progress
1 parent f156a8b commit 9a30b33

File tree

12 files changed

+310
-50
lines changed

12 files changed

+310
-50
lines changed

pkg/demoinfocs/common/entity_util.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,23 @@ func getInt(entity st.Entity, propName string) int {
77
return 0
88
}
99

10-
return entity.PropertyValueMust(propName).IntVal
10+
return entity.PropertyValueMust(propName).Int()
1111
}
1212

1313
func getFloat(entity st.Entity, propName string) float32 {
1414
if entity == nil {
1515
return 0
1616
}
1717

18-
return entity.PropertyValueMust(propName).FloatVal
18+
return entity.PropertyValueMust(propName).Float()
1919
}
2020

2121
func getString(entity st.Entity, propName string) string {
2222
if entity == nil {
2323
return ""
2424
}
2525

26-
return entity.PropertyValueMust(propName).StringVal
26+
return entity.PropertyValueMust(propName).String()
2727
}
2828

2929
func getBool(entity st.Entity, propName string) bool {

pkg/demoinfocs/datatables.go

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,19 @@ func (p *parser) bindBomb() {
8282
bomb.LastOnGroundPosition = pos
8383
})
8484

85-
bombEntity.Property("m_hOwner").OnUpdate(func(val st.PropertyValue) {
86-
bomb.Carrier = p.gameState.Participants().FindByHandle(val.IntVal)
87-
})
85+
if p.isSource2() {
86+
bombEntity.Property("m_hOwnerEntity").OnUpdate(func(val st.PropertyValue) {
87+
bomb.Carrier = p.gameState.Participants().FindByHandle64(val.Handle())
88+
})
89+
} else {
90+
bombEntity.Property("m_hOwner").OnUpdate(func(val st.PropertyValue) {
91+
if val.IntVal < 0 {
92+
panic("bomb owner < 0")
93+
}
94+
95+
bomb.Carrier = p.gameState.Participants().FindByHandle(val.IntVal)
96+
})
97+
}
8898

8999
bombEntity.Property("m_bStartedArming").OnUpdate(func(val st.PropertyValue) {
90100
if val.IntVal != 0 {
@@ -107,7 +117,6 @@ func (p *parser) bindBomb() {
107117
}
108118

109119
func (p *parser) bindTeamStates() {
110-
fmt.Println(p.stParser.ServerClasses().FindByName("CCSTeam"))
111120
p.stParser.ServerClasses().FindByName("CCSTeam").OnEntityCreated(func(entity st.Entity) {
112121
teamVal := entity.PropertyValueMust("m_szTeamname")
113122
team := teamVal.StringVal
@@ -170,20 +179,30 @@ func (p *parser) bindBombSites() {
170179
t := new(boundingBoxInformation)
171180
p.triggers[baseTrigger.ID()] = t
172181

173-
baseTrigger.BindProperty("m_Collision.m_vecMins", &t.min, st.ValTypeVector)
174-
baseTrigger.BindProperty("m_Collision.m_vecMaxs", &t.max, st.ValTypeVector)
182+
if p.isSource2() {
183+
baseTrigger.BindProperty("m_vecMins", &t.min, st.ValTypeVector)
184+
baseTrigger.BindProperty("m_vecMaxs", &t.max, st.ValTypeVector)
185+
} else {
186+
baseTrigger.BindProperty("m_Collision.m_vecMins", &t.min, st.ValTypeVector)
187+
baseTrigger.BindProperty("m_Collision.m_vecMaxs", &t.max, st.ValTypeVector)
188+
}
175189
})
176190
}
177191

178192
func (p *parser) bindPlayers() {
179-
fmt.Println(p.stParser.ServerClasses().FindByName("CCSPlayerPawn"))
180-
p.stParser.ServerClasses().FindByName("CCSPlayerPawn").OnEntityCreated(func(player st.Entity) {
181-
p.bindNewPlayer(player)
182-
})
193+
if p.isSource2() {
194+
p.stParser.ServerClasses().FindByName("CCSPlayerPawn").OnEntityCreated(func(player st.Entity) {
195+
p.bindNewPlayer(player)
196+
})
197+
} else {
198+
p.stParser.ServerClasses().FindByName("CCSPlayerResource").OnEntityCreated(func(entity st.Entity) {
199+
p.gameState.playerResourceEntity = entity
200+
})
183201

184-
p.stParser.ServerClasses().FindByName("CCSPlayerResource").OnEntityCreated(func(entity st.Entity) {
185-
p.gameState.playerResourceEntity = entity
186-
})
202+
p.stParser.ServerClasses().FindByName("CCSPlayer").OnEntityCreated(func(player st.Entity) {
203+
p.bindNewPlayer(player)
204+
})
205+
}
187206
}
188207

189208
func (p *parser) getOrCreatePlayer(entityID int, rp *common.PlayerInfo) (isNew bool, player *common.Player) {
@@ -263,18 +282,32 @@ func (p *parser) bindNewPlayer(playerEntity st.Entity) {
263282
pl.FlashDuration = val.FloatVal
264283
})
265284

266-
p.bindPlayerWeapons(playerEntity, pl)
285+
if !p.isSource2() {
286+
p.bindPlayerWeapons(playerEntity, pl) // FIXME: make weapons work for S2
267287

268-
// Active weapon
269-
playerEntity.Property("m_hActiveWeapon").OnUpdate(func(val st.PropertyValue) {
270-
pl.IsReloading = false
271-
})
288+
for i := 0; i < 32; i++ {
289+
i2 := i // Copy so it stays the same
290+
playerEntity.BindProperty("m_iAmmo."+fmt.Sprintf("%03d", i2), &pl.AmmoLeft[i2], st.ValTypeInt)
291+
}
292+
}
272293

273-
for i := 0; i < 32; i++ {
274-
i2 := i // Copy so it stays the same
275-
playerEntity.BindProperty("m_iAmmo."+fmt.Sprintf("%03d", i2), &pl.AmmoLeft[i2], st.ValTypeInt)
294+
var (
295+
activeWep st.Property
296+
spottedByPrefix string
297+
)
298+
299+
if p.isSource2() {
300+
activeWep = playerEntity.Property("m_pWeaponServices.m_hActiveWeapon")
301+
spottedByPrefix = "m_bSpottedByMask.000"
302+
} else {
303+
activeWep = playerEntity.Property("m_hActiveWeapon")
304+
spottedByPrefix = "m_bSpottedByMask.00"
276305
}
277306

307+
activeWep.OnUpdate(func(val st.PropertyValue) {
308+
pl.IsReloading = false
309+
})
310+
278311
playerEntity.Property("m_bIsDefusing").OnUpdate(func(val st.PropertyValue) {
279312
if p.gameState.currentDefuser == pl && pl.IsDefusing && val.IntVal == 0 {
280313
p.eventDispatcher.Dispatch(events.BombDefuseAborted{Player: pl})
@@ -284,14 +317,14 @@ func (p *parser) bindNewPlayer(playerEntity st.Entity) {
284317
pl.IsDefusing = val.IntVal != 0
285318
})
286319

287-
spottedByMaskProp := playerEntity.Property("m_bSpottedByMask.000")
320+
spottedByMaskProp := playerEntity.Property(spottedByPrefix + "0")
288321
if spottedByMaskProp != nil {
289322
spottersChanged := func(val st.PropertyValue) {
290323
p.eventDispatcher.Dispatch(events.PlayerSpottersChanged{Spotted: pl})
291324
}
292325

293326
spottedByMaskProp.OnUpdate(spottersChanged)
294-
playerEntity.Property("m_bSpottedByMask.001").OnUpdate(spottersChanged)
327+
playerEntity.Property(spottedByPrefix + "1").OnUpdate(spottersChanged)
295328
}
296329

297330
if isNew {
@@ -415,7 +448,7 @@ func (p *parser) bindGrenadeProjectiles(entity st.Entity) {
415448
})
416449

417450
entity.Property("m_hOwnerEntity").OnUpdate(func(val st.PropertyValue) {
418-
proj.Owner = p.gameState.Participants().FindByHandle(val.IntVal)
451+
proj.Owner = p.gameState.Participants().FindByHandle64(val.Handle())
419452
})
420453

421454
entity.OnPositionUpdate(func(newPos r3.Vector) {
@@ -550,12 +583,16 @@ func (p *parser) infernoExpired(inf *common.Inferno) {
550583

551584
//nolint:funlen
552585
func (p *parser) bindGameRules() {
553-
grPrefix := func(s string) string {
554-
return fmt.Sprintf("%s.%s", gameRulesPrefix, s)
555-
}
556-
557586
gameRules := p.ServerClasses().FindByName("CCSGameRulesProxy")
558587
gameRules.OnEntityCreated(func(entity st.Entity) {
588+
grPrefix := func(s string) string {
589+
if p.isSource2() {
590+
return fmt.Sprintf("%s.%s", gameRulesPrefixS2, s)
591+
}
592+
593+
return fmt.Sprintf("%s.%s", gameRulesPrefix, s)
594+
}
595+
559596
p.gameState.rules.entity = entity
560597

561598
entity.Property(grPrefix("m_gamePhase")).OnUpdate(func(val st.PropertyValue) {

pkg/demoinfocs/demoinfocs_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,8 @@ func TestS2(t *testing.T) {
217217
_, err = p.ParseHeader()
218218
assertions.NoError(err, "error returned by Parser.ParseHeader()")
219219

220-
p.RegisterEventHandler(func(event events.GenericGameEvent) {
221-
//fmt.Println(event.Name, event)
220+
p.RegisterEventHandler(func(e any) {
221+
fmt.Printf("%#v\n", e)
222222
})
223223

224224
t.Log("Parsing to end")

pkg/demoinfocs/fake/game_state.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (gs *GameState) Rules() demoinfocs.GameRules {
9090
return gs.Called().Get(0).(demoinfocs.GameRules)
9191
}
9292

93-
// PlayerResourceEntity is a mock-implementation of GameState.PlayerResorceEntity().
93+
// PlayerResourceEntity is a mock-implementation of GameState.PlayerResourceEntity().
9494
func (gs *GameState) PlayerResourceEntity() st.Entity {
9595
return gs.Called().Get(0).(st.Entity)
9696
}

pkg/demoinfocs/fake/participants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ func (ptcp *Participants) FindByHandle(handle int) *common.Player {
5454
return ptcp.Called().Get(0).(*common.Player)
5555
}
5656

57+
// FindByHandle64 is a mock-implementation of Participants.FindByHandle64().
58+
func (ptcp *Participants) FindByHandle64(handle uint64) *common.Player {
59+
return ptcp.Called().Get(0).(*common.Player)
60+
}
61+
5762
// SpottersOf is a mock-implementation of Participants.SpottersOf().
5863
func (ptcp *Participants) SpottersOf(spotted *common.Player) []*common.Player {
5964
return ptcp.Called().Get(0).([]*common.Player)

pkg/demoinfocs/game_state.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,8 @@ func (ptcp participants) TeamMembers(team common.Team) []*common.Player {
361361
// The entity-handle is often used in entity-properties when referencing other entities such as a weapon's owner.
362362
//
363363
// Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).
364+
//
365+
// Deprecated: Use FindByHandle64 instead.
364366
func (ptcp participants) FindByHandle(handle int) *common.Player {
365367
if handle == constants.InvalidEntityHandle {
366368
return nil
@@ -371,6 +373,20 @@ func (ptcp participants) FindByHandle(handle int) *common.Player {
371373
return ptcp.playersByEntityID[entityID]
372374
}
373375

376+
// FindByHandle64 attempts to find a player by his entity-handle.
377+
// The entity-handle is often used in entity-properties when referencing other entities such as a weapon's owner.
378+
//
379+
// Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).
380+
func (ptcp participants) FindByHandle64(handle uint64) *common.Player {
381+
if handle == constants.InvalidEntityHandle {
382+
return nil
383+
}
384+
385+
entityID := handle & constants.EntityHandleIndexMask
386+
387+
return ptcp.playersByEntityID[int(entityID)]
388+
}
389+
374390
func (ptcp participants) initializeSliceFromByUserID() ([]*common.Player, map[int]*common.Player) {
375391
byUserID := ptcp.ByUserID()
376392
return make([]*common.Player, 0, len(byUserID)), byUserID

pkg/demoinfocs/parser.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,10 @@ func (p *parser) initMsgQueue(buf int) {
415415
p.msgDispatcher.AddQueues(p.msgQueue)
416416
}
417417

418+
func (p *parser) isSource2() bool {
419+
return true
420+
}
421+
418422
type demoInfoProvider struct {
419423
parser *parser
420424
}

pkg/demoinfocs/parsing.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const (
2828
playerWeaponPrefix = "m_hMyWeapons."
2929
playerWeaponPrePrefix = "bcc_nonlocaldata."
3030
gameRulesPrefix = "cs_gamerules_data"
31+
gameRulesPrefixS2 = "m_pGameRules"
3132
)
3233

3334
// Parsing errors
@@ -324,6 +325,8 @@ func (p *parser) parseFrameS2() bool {
324325
tick = 0
325326
}
326327

328+
p.msgQueue <- ingameTickNumber(int32(tick))
329+
327330
size := p.bitReader.ReadVarInt32()
328331

329332
buf := p.bitReader.ReadBytes(int(size))
@@ -367,7 +370,8 @@ func (p *parser) parseFrameS2() bool {
367370
p.handleStringTables(m)
368371
}
369372

370-
p.msgQueue <- ingameTickNumber(int32(tick))
373+
// Queue up some post processing
374+
p.msgQueue <- frameParsedToken
371375

372376
return msgType != msgs2.EDemoCommands_DEM_Stop
373377
}

pkg/demoinfocs/participants_interface.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,14 @@ type Participants interface {
4141
// The entity-handle is often used in entity-properties when referencing other entities such as a weapon's owner.
4242
//
4343
// Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).
44+
//
45+
// Deprecated: Use FindByHandle64 instead.
4446
FindByHandle(handle int) *common.Player
47+
// FindByHandle64 attempts to find a player by his entity-handle.
48+
// The entity-handle is often used in entity-properties when referencing other entities such as a weapon's owner.
49+
//
50+
// Returns nil if not found or if handle == invalidEntityHandle (used when referencing no entity).
51+
FindByHandle64(handle uint64) *common.Player
4552
// SpottersOf returns a list of all players who have spotted the passed player.
4653
// This is NOT "Line of Sight" / FOV - look up "CSGO TraceRay" for that.
4754
// May not behave as expected with multiple spotters.

pkg/demoinfocs/sendtables/propdecoder.go

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,84 @@ var propDecoder propertyDecoder
9090
// PropertyValue stores parsed & decoded send-table values.
9191
// For instance player health, location etc.
9292
type PropertyValue struct {
93-
VectorVal r3.Vector
94-
IntVal int
95-
Int64Val int64
96-
ArrayVal []PropertyValue
97-
StringVal string
98-
FloatVal float32
93+
VectorVal r3.Vector // Deprecated, use R3Vec() instead
94+
IntVal int // Deprecated, use Int() instead
95+
Int64Val int64 // Deprecated, use Int64() instead
96+
ArrayVal []PropertyValue // Deprecated.
97+
StringVal string // Deprecated, use String() instead
98+
FloatVal float32 // Deprecated, use Float() instead
9999
Any any
100+
S2 bool
101+
}
102+
103+
func (v PropertyValue) R3Vec() r3.Vector {
104+
if v.S2 {
105+
fs := v.Any.([]float32)
106+
107+
return r3.Vector{
108+
X: float64(fs[0]),
109+
Y: float64(fs[1]),
110+
Z: float64(fs[2]),
111+
}
112+
}
113+
114+
return v.VectorVal
115+
}
116+
117+
func (v PropertyValue) Int() int {
118+
if v.S2 {
119+
return int(v.Any.(int32))
120+
}
121+
122+
return v.IntVal
123+
}
124+
125+
func (v PropertyValue) Int64() int64 {
126+
if v.S2 {
127+
return v.Any.(int64)
128+
}
129+
130+
return v.Int64Val
131+
}
132+
133+
func (v PropertyValue) S2UInt64() uint64 {
134+
return v.Any.(uint64)
135+
}
136+
137+
func (v PropertyValue) Handle() uint64 {
138+
if v.S2 {
139+
return v.S2UInt64()
140+
}
141+
142+
if v.IntVal < 0 {
143+
panic("Handle is negative")
144+
}
145+
146+
return uint64(v.IntVal)
147+
}
148+
149+
func (v PropertyValue) Float() float32 {
150+
if v.S2 {
151+
return v.Any.(float32)
152+
}
153+
154+
return v.FloatVal
155+
}
156+
157+
func (v PropertyValue) String() string {
158+
if v.S2 {
159+
return v.Any.(string)
160+
}
161+
162+
return v.StringVal
100163
}
101164

102165
// BoolVal returns true if IntVal > 0.
103166
func (v PropertyValue) BoolVal() bool {
167+
if v.S2 {
168+
return v.Any.(bool)
169+
}
170+
104171
return v.IntVal > 0
105172
}
106173

0 commit comments

Comments
 (0)