-
Notifications
You must be signed in to change notification settings - Fork 90
/
common.go
305 lines (249 loc) · 9.25 KB
/
common.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// Package common contains common types, constants and functions used over different demoinfocs packages.
package common
import (
"fmt"
"math/rand"
"strconv"
"strings"
"time"
"github.com/golang/geo/r3"
st "github.com/markus-wa/demoinfocs-golang/v4/pkg/demoinfocs/sendtables"
)
// Team is the type for the various TeamXYZ constants.
type Team byte
// Team constants give information about which team a player is on.
const (
TeamUnassigned Team = 0
TeamSpectators Team = 1
TeamTerrorists Team = 2
TeamCounterTerrorists Team = 3
)
// DemoHeader contains information from a demo's header.
type DemoHeader struct {
Filestamp string // aka. File-type, must be HL2DEMO
Protocol int // Should be 4
NetworkProtocol int // Not sure what this is for
ServerName string // Server's 'hostname' config value
ClientName string // Usually 'GOTV Demo'
MapName string // E.g. de_cache, de_nuke, cs_office, etc.
GameDirectory string // Usually 'csgo'
PlaybackTime time.Duration // Demo duration in seconds (= PlaybackTicks / Server's tickrate)
PlaybackTicks int // Game duration in ticks (= PlaybackTime * Server's tickrate)
PlaybackFrames int // Amount of 'frames' aka demo-ticks recorded (= PlaybackTime * Demo's recording rate)
SignonLength int // Length of the Signon package in bytes
}
// FrameRate returns the frame rate of the demo (frames / demo-ticks per second).
// Not necessarily the tick-rate the server ran on during the game.
//
// Returns 0 if PlaybackTime or PlaybackFrames are 0 (corrupt demo headers).
func (h *DemoHeader) FrameRate() float64 {
if h.PlaybackTime == 0 {
return 0
}
return float64(h.PlaybackFrames) / h.PlaybackTime.Seconds()
}
// FrameTime returns the time a frame / demo-tick takes in seconds.
//
// Returns 0 if PlaybackTime or PlaybackFrames are 0 (corrupt demo headers).
func (h *DemoHeader) FrameTime() time.Duration {
if h.PlaybackFrames == 0 {
return 0
}
return time.Duration(h.PlaybackTime.Nanoseconds() / int64(h.PlaybackFrames))
}
// GrenadeProjectile is a grenade thrown intentionally by a player. It is used to track grenade projectile
// positions between the time at which they are thrown and until they detonate.
type GrenadeProjectile struct {
Entity st.Entity
WeaponInstance *Equipment
Thrower *Player // Always seems to be the same as Owner, even if the grenade was picked up
Owner *Player // Always seems to be the same as Thrower, even if the grenade was picked up
// Deprecated: use Trajectory2 instead
Trajectory []r3.Vector // List of all known locations of the grenade up to the current point
Trajectory2 []TrajectoryEntry // List of all known locations and the point in time of the grenade up to the current point
// uniqueID is used to distinguish different grenades (which potentially have the same, reused entityID) from each other.
uniqueID int64
}
// Position returns the current position of the grenade projectile in world coordinates.
func (g *GrenadeProjectile) Position() r3.Vector {
return g.Entity.Position()
}
// Velocity returns the projectile's velocity.
func (g *GrenadeProjectile) Velocity() r3.Vector {
return g.Entity.PropertyValueMust("m_vecVelocity").VectorVal
}
// UniqueID returns the unique id of the grenade.
// The unique id is a random int generated internally by this library and can be used to differentiate
// grenades from each other. This is needed because demo-files reuse entity ids.
func (g *GrenadeProjectile) UniqueID() int64 {
return g.uniqueID
}
// NewGrenadeProjectile creates a grenade projectile and sets the Unique-ID.
//
// Intended for internal use only.
func NewGrenadeProjectile() *GrenadeProjectile {
return &GrenadeProjectile{uniqueID: rand.Int63()} //nolint:gosec
}
// Bomb tracks the bomb's position, and the player carrying it, if any.
type Bomb struct {
// Intended for internal use only. Use Position() instead.
// Contains the last location of the dropped or planted bomb.
LastOnGroundPosition r3.Vector
Carrier *Player
}
// Position returns the current position of the bomb.
// This is either the position of the player holding it
// or LastOnGroundPosition if it's dropped or planted.
func (b *Bomb) Position() r3.Vector {
if b.Carrier != nil {
return b.Carrier.Position()
}
return b.LastOnGroundPosition
}
// TeamState contains a team's ID, score, clan name & country flag.
type TeamState struct {
team Team
membersCallback func(Team) []*Player
demoInfoProvider demoInfoProvider
Entity st.Entity
// Terrorist TeamState for CTs, CT TeamState for Terrorists
Opponent *TeamState
}
// Team returns the team for which the TeamState contains data.
func (ts *TeamState) Team() Team {
return ts.team
}
// ID returns the team ID, this stays the same even after switching sides.
func (ts *TeamState) ID() int {
if ts.demoInfoProvider.IsSource2() {
return int(getUInt64(ts.Entity, "m_iTeamNum"))
}
return getInt(ts.Entity, "m_iTeamNum")
}
// Score returns the current score of the team (usually 0-16 without overtime).
func (ts *TeamState) Score() int {
var propName string
if ts.demoInfoProvider.IsSource2() {
propName = "m_iScore"
} else {
propName = "m_scoreTotal"
}
return getInt(ts.Entity, propName)
}
// ClanName returns the team name (e.g. Fnatic).
func (ts *TeamState) ClanName() string {
return getString(ts.Entity, "m_szClanTeamname")
}
// Flag returns the flag code (e.g. DE, FR, etc.).
//
// Watch out, in some demos this is upper-case and in some lower-case.
func (ts *TeamState) Flag() string {
return getString(ts.Entity, "m_szTeamFlagImage")
}
// Members returns the players that are members of the team.
func (ts *TeamState) Members() []*Player {
return ts.membersCallback(ts.team)
}
// CurrentEquipmentValue returns the cumulative value of all equipment currently owned by the members of the team.
func (ts *TeamState) CurrentEquipmentValue() (value int) {
for _, pl := range ts.Members() {
value += pl.EquipmentValueCurrent()
}
return
}
// RoundStartEquipmentValue returns the cumulative value of all equipment owned by the members of the team at the start of the current round.
func (ts *TeamState) RoundStartEquipmentValue() (value int) {
for _, pl := range ts.Members() {
value += pl.EquipmentValueRoundStart()
}
return
}
// FreezeTimeEndEquipmentValue returns the cumulative value of all equipment owned by the members of the team at the end of the freeze-time of the current round.
func (ts *TeamState) FreezeTimeEndEquipmentValue() (value int) {
for _, pl := range ts.Members() {
value += pl.EquipmentValueFreezeTimeEnd()
}
return
}
// MoneySpentThisRound returns the total amount of cash spent by the whole team in the current round.
func (ts *TeamState) MoneySpentThisRound() (value int) {
for _, pl := range ts.Members() {
value += pl.MoneySpentThisRound()
}
return
}
// MoneySpentTotal returns the total amount of cash spent by the whole team during the whole game up to the current point.
func (ts *TeamState) MoneySpentTotal() (value int) {
for _, pl := range ts.Members() {
value += pl.MoneySpentTotal()
}
return
}
// NewTeamState creates a new TeamState with the given Team and members callback function.
func NewTeamState(team Team, membersCallback func(Team) []*Player, demoInfoProvider demoInfoProvider) TeamState {
return TeamState{
team: team,
membersCallback: membersCallback,
demoInfoProvider: demoInfoProvider,
}
}
// TrajectoryEntry represents the location of a grenade's trajectory at a specific point in time.
type TrajectoryEntry struct {
Position r3.Vector
FrameID int
Time time.Duration
}
// ConvertSteamIDTxtTo32 converts a Steam-ID in text format to a 32-bit variant.
// See https://developer.valvesoftware.com/wiki/SteamID
func ConvertSteamIDTxtTo32(steamID string) (uint32, error) {
steamID = strings.TrimSuffix(steamID, "]") // Source 2 has [U:1:397560266] instead of STEAM_0:1:198780133
arr := strings.Split(steamID, ":")
if len(arr) != 3 {
return 0, fmt.Errorf("SteamID '%s' not well formed", steamID)
}
Y, err := strconv.ParseUint(arr[1], 10, 32)
if err != nil {
return 0, err
}
Z, err := strconv.ParseUint(arr[2], 10, 32)
if err != nil {
return 0, err
}
return uint32((Z << 1) + Y), nil
}
const steamID64IndividualIdentifier = 0x0110000100000000
// ConvertSteamID32To64 converts a Steam-ID in 32-bit format to a 64-bit variant.
// See https://developer.valvesoftware.com/wiki/SteamID
func ConvertSteamID32To64(steamID32 uint32) uint64 {
return steamID64IndividualIdentifier + uint64(steamID32)
}
// ConvertSteamID64To32 converts a Steam-ID in 64-bit format to a 32-bit variant.
// See https://developer.valvesoftware.com/wiki/SteamID
func ConvertSteamID64To32(steamID64 uint64) uint32 {
return uint32(steamID64 - steamID64IndividualIdentifier)
}
// Color is the type for the various colors constants.
type Color int
// Color constants give information about which color a player has.
const (
Grey Color = iota - 1
Yellow
Purple
Green
Blue
Orange
)
var strColors = map[Color]string{
Grey: "Grey",
Yellow: "Yellow",
Purple: "Purple",
Green: "Green",
Blue: "Blue",
Orange: "Orange",
}
func (c Color) String() string {
if _, exists := strColors[c]; !exists {
return "Unknown-Color"
}
return strColors[c]
}