Skip to content

Commit faa66bb

Browse files
committed
Merge remote-tracking branch 'origin/master' into s2-fake-CMsgSource1LegacyGameEventList
2 parents 3c4b79f + 33abbfb commit faa66bb

File tree

10 files changed

+270
-101
lines changed

10 files changed

+270
-101
lines changed

.github/ISSUE_TEMPLATE/bug_report.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func x() {
2020
A clear and concise description of what you expected to happen.
2121

2222
**Library version**
23-
e.g. v1.x.x
23+
vX.X.X
2424

2525
**Additional context**
2626
Add any other context about the problem here - like your OS if that could be relevant.

pkg/demoinfocs/common/common.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,13 @@ func (h *DemoHeader) FrameTime() time.Duration {
6767
type GrenadeProjectile struct {
6868
Entity st.Entity
6969
WeaponInstance *Equipment
70-
Thrower *Player // Always seems to be the same as Owner, even if the grenade was picked up
71-
Owner *Player // Always seems to be the same as Thrower, even if the grenade was picked up
72-
Trajectory []r3.Vector // List of all known locations of the grenade up to the current point
70+
Thrower *Player // Always seems to be the same as Owner, even if the grenade was picked up
71+
Owner *Player // Always seems to be the same as Thrower, even if the grenade was picked up
72+
73+
// Deprecated: use Trajectory2 instead
74+
Trajectory []r3.Vector // List of all known locations of the grenade up to the current point
75+
76+
Trajectory2 []TrajectoryEntry // List of all known locations and the point in time of the grenade up to the current point
7377

7478
// uniqueID is used to distinguish different grenades (which potentially have the same, reused entityID) from each other.
7579
uniqueID int64
@@ -225,6 +229,13 @@ func NewTeamState(team Team, membersCallback func(Team) []*Player, demoInfoProvi
225229
}
226230
}
227231

232+
// TrajectoryEntry represents the location of a grenade's trajectory at a specific point in time.
233+
type TrajectoryEntry struct {
234+
Position r3.Vector
235+
FrameID int
236+
Time time.Duration
237+
}
238+
228239
// ConvertSteamIDTxtTo32 converts a Steam-ID in text format to a 32-bit variant.
229240
// See https://developer.valvesoftware.com/wiki/SteamID
230241
func ConvertSteamIDTxtTo32(steamID string) (uint32, error) {

pkg/demoinfocs/common/common_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,14 @@ type demoInfoProviderMock struct {
213213
tickRate float64
214214
ingameTick int
215215
playersByHandle map[int]*Player
216+
entitiesByHandle map[uint64]st.Entity
216217
playerResourceEntity st.Entity
217218
equipment *Equipment
218219
isSource2 bool
219220
}
220221

221222
func (p demoInfoProviderMock) FindEntityByHandle(handle uint64) st.Entity {
222-
panic("implement me")
223+
return p.entitiesByHandle[handle]
223224
}
224225

225226
func (p demoInfoProviderMock) IsSource2() bool {

pkg/demoinfocs/common/inferno.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,22 @@ func (inf *Inferno) Fires() Fires {
7474
}
7575
for i := 0; i < nFires; i++ {
7676
iStr := fmt.Sprintf(iFormat, i)
77-
offset := r3.Vector{
78-
X: float64(entity.PropertyValueMust("m_fireXDelta." + iStr).Int()),
79-
Y: float64(entity.PropertyValueMust("m_fireYDelta." + iStr).Int()),
80-
Z: float64(entity.PropertyValueMust("m_fireZDelta." + iStr).Int()),
81-
}
8277

8378
fire := Fire{
84-
Vector: origin.Add(offset),
8579
IsBurning: entity.PropertyValueMust("m_bFireIsBurning." + iStr).BoolVal(),
8680
}
8781

82+
if prop := entity.Property("m_firePositions." + iStr); prop != nil {
83+
fire.Vector = prop.Value().R3Vec()
84+
} else {
85+
offset := r3.Vector{
86+
X: float64(entity.PropertyValueMust("m_fireXDelta." + iStr).Int()),
87+
Y: float64(entity.PropertyValueMust("m_fireYDelta." + iStr).Int()),
88+
Z: float64(entity.PropertyValueMust("m_fireZDelta." + iStr).Int()),
89+
}
90+
fire.Vector = origin.Add(offset)
91+
}
92+
8893
fires = append(fires, fire)
8994
}
9095

pkg/demoinfocs/common/player.go

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,24 +15,25 @@ import (
1515
type Player struct {
1616
demoInfoProvider demoInfoProvider // provider for demo info such as tick-rate or current tick
1717

18-
SteamID64 uint64 // 64-bit representation of the user's Steam ID. See https://developer.valvesoftware.com/wiki/SteamID
19-
LastAlivePosition r3.Vector // The location where the player was last alive. Should be equal to Position if the player is still alive.
20-
UserID int // Mostly used in game-events to address this player
21-
Name string // Steam / in-game user name
22-
Inventory map[int]*Equipment // All weapons / equipment the player is currently carrying. See also Weapons().
23-
AmmoLeft [32]int // Ammo left for special weapons (e.g. grenades), index corresponds Equipment.AmmoType
24-
EntityID int // Usually the same as Entity.ID() but may be different between player death and re-spawn.
25-
Entity st.Entity // May be nil between player-death and re-spawn
26-
FlashDuration float32 // Blindness duration from the flashbang currently affecting the player (seconds)
27-
FlashTick int // In-game tick at which the player was last flashed
28-
TeamState *TeamState // When keeping the reference make sure you notice when the player changes teams
29-
Team Team // Team identifier for the player (e.g. TeamTerrorists or TeamCounterTerrorists).
30-
IsBot bool // True if this is a bot-entity. See also IsControllingBot and ControlledBot().
31-
IsConnected bool
32-
IsDefusing bool
33-
IsPlanting bool
34-
IsReloading bool
35-
IsUnknown bool // Used to identify unknown/broken players. see https://github.com/markus-wa/demoinfocs-golang/issues/162
18+
SteamID64 uint64 // 64-bit representation of the user's Steam ID. See https://developer.valvesoftware.com/wiki/SteamID
19+
LastAlivePosition r3.Vector // The location where the player was last alive. Should be equal to Position if the player is still alive.
20+
UserID int // Mostly used in game-events to address this player
21+
Name string // Steam / in-game user name
22+
Inventory map[int]*Equipment // All weapons / equipment the player is currently carrying. See also Weapons().
23+
AmmoLeft [32]int // Ammo left for special weapons (e.g. grenades), index corresponds Equipment.AmmoType
24+
EntityID int // Usually the same as Entity.ID() but may be different between player death and re-spawn.
25+
Entity st.Entity // May be nil between player-death and re-spawn
26+
FlashDuration float32 // Blindness duration from the flashbang currently affecting the player (seconds)
27+
FlashTick int // In-game tick at which the player was last flashed
28+
TeamState *TeamState // When keeping the reference make sure you notice when the player changes teams
29+
Team Team // Team identifier for the player (e.g. TeamTerrorists or TeamCounterTerrorists).
30+
IsBot bool // True if this is a bot-entity. See also IsControllingBot and ControlledBot().
31+
IsConnected bool
32+
IsDefusing bool
33+
IsPlanting bool
34+
IsReloading bool
35+
IsUnknown bool // Used to identify unknown/broken players. see https://github.com/markus-wa/demoinfocs-golang/issues/162
36+
PreviousFramePosition r3.Vector // CS2 only, used to compute velocity as it's not networked in CS2 demos
3637
}
3738

3839
func (p *Player) PlayerPawnEntity() st.Entity {
@@ -380,7 +381,9 @@ func (p *Player) Armor() int {
380381
// CS2 values:
381382
// -1 -> Not available, demo probably not coming from a Valve server
382383
// 0 -> None?
383-
// 11 -> Classic Competitive
384+
// 7 -> Wingman 2v2
385+
// 11 -> Premier mode
386+
// 12 -> Classic Competitive
384387
func (p *Player) RankType() int {
385388
if p.demoInfoProvider.IsSource2() {
386389
return getInt(p.Entity, "m_iCompetitiveRankType")
@@ -519,7 +522,14 @@ func (p *Player) PositionEyes() r3.Vector {
519522
// Velocity returns the player's velocity.
520523
func (p *Player) Velocity() r3.Vector {
521524
if p.demoInfoProvider.IsSource2() {
522-
panic("Velocity() is not supported for Source 2 demos")
525+
t := 64.0
526+
diff := p.Position().Sub(p.PreviousFramePosition)
527+
528+
return r3.Vector{
529+
X: diff.X * t,
530+
Y: diff.Y * t,
531+
Z: diff.Z * t,
532+
}
523533
}
524534

525535
if p.Entity == nil {
@@ -799,8 +809,9 @@ type demoInfoProvider interface {
799809
// Intended for internal use only.
800810
func NewPlayer(demoInfoProvider demoInfoProvider) *Player {
801811
return &Player{
802-
Inventory: make(map[int]*Equipment),
803-
demoInfoProvider: demoInfoProvider,
812+
Inventory: make(map[int]*Equipment),
813+
demoInfoProvider: demoInfoProvider,
814+
PreviousFramePosition: r3.Vector{},
804815
}
805816
}
806817

pkg/demoinfocs/common/player_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,46 @@ func TestPlayer_Velocity(t *testing.T) {
428428
assert.Equal(t, expected, pl.Velocity())
429429
}
430430

431+
func createPlayerForVelocityTest() *Player {
432+
controllerEntity := entityWithProperties([]fakeProp{
433+
{propName: "m_hPlayerPawn", value: st.PropertyValue{Any: uint64(1), S2: true}},
434+
})
435+
pawnEntity := new(stfake.Entity)
436+
position := r3.Vector{X: 20, Y: 300, Z: 100}
437+
438+
pawnEntity.On("Position").Return(position)
439+
440+
pl := &Player{
441+
Entity: controllerEntity,
442+
}
443+
444+
demoInfoProvider := demoInfoProviderMock{
445+
isSource2: true,
446+
entitiesByHandle: map[uint64]st.Entity{
447+
1: pawnEntity,
448+
},
449+
}
450+
pl.demoInfoProvider = demoInfoProvider
451+
452+
return pl
453+
}
454+
455+
func TestPlayer_VelocityS2(t *testing.T) {
456+
pl := createPlayerForVelocityTest()
457+
pl.PreviousFramePosition = r3.Vector{X: 10, Y: 200, Z: 50}
458+
459+
expected := r3.Vector{X: 640, Y: 6400, Z: 3200}
460+
assert.Equal(t, expected, pl.Velocity())
461+
}
462+
463+
func TestPlayer_VelocityDidNotChangeS2(t *testing.T) {
464+
pl := createPlayerForVelocityTest()
465+
pl.PreviousFramePosition = r3.Vector{X: 20, Y: 300, Z: 100}
466+
467+
expected := r3.Vector{X: 0, Y: 0, Z: 0}
468+
assert.Equal(t, expected, pl.Velocity())
469+
}
470+
431471
func TestPlayer_Velocity_EntityNil(t *testing.T) {
432472
pl := new(Player)
433473
pl.demoInfoProvider = s1DemoInfoProvider

0 commit comments

Comments
 (0)