Skip to content

Commit edd363a

Browse files
committed
Expose datatables (beta)
1 parent 0e75c53 commit edd363a

File tree

9 files changed

+103
-97
lines changed

9 files changed

+103
-97
lines changed

events/events.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,3 +296,8 @@ type ItemDropEvent struct {
296296
Weapon common.Equipment
297297
Player *common.Player
298298
}
299+
300+
// DataTablesParsedEvent signals that the datatables were parsed.
301+
// You can use the Parser.SendTableParser() after this event to register update notification on entities & properties.
302+
// DataTablesParsedEvent is a beta feature, it may be replaced or changed without notice.
303+
type DataTablesParsedEvent struct{}

parser.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import (
2222
// Use Parser.RegisterEventHandler() to receive notifications about events.
2323
type Parser struct {
2424
bitReader *bit.BitReader
25-
stParser st.Parser
25+
stParser st.SendTableParser
2626
msgDispatcher dp.Dispatcher
2727
eventDispatcher dp.Dispatcher
2828
msgQueue chan interface{}
@@ -66,6 +66,12 @@ func (bbi boundingBoxInformation) contains(point r3.Vector) bool {
6666
point.Z >= bbi.min.Z && point.Z <= bbi.max.Z
6767
}
6868

69+
// SendTableParser returns the sendtable parser.
70+
// This is a beta feature and may be changed or replaced without notice.
71+
func (p *Parser) SendTableParser() *st.SendTableParser {
72+
return &p.stParser
73+
}
74+
6975
// Header returns the DemoHeader which contains the demo's metadata.
7076
func (p *Parser) Header() common.DemoHeader {
7177
return *p.header

parsing.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ func (p *Parser) parseFrame() bool {
192192
p.mapEquipment()
193193
p.bindEntities()
194194

195+
p.eventDispatcher.Dispatch(events.DataTablesParsedEvent{})
196+
195197
case dcStringTables:
196198
p.msgDispatcher.SyncQueues(p.msgQueue)
197199

sendtables/constants.go

Lines changed: 0 additions & 48 deletions
This file was deleted.

sendtables/entity.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ func (e *Entity) Props() []PropertyEntry {
2020
}
2121

2222
// FindProperty finds a property on the Entity by name.
23+
// Returns nil if the property wasn't found.
24+
// Panics if more than one property with the same name was found.
2325
func (e *Entity) FindProperty(name string) *PropertyEntry {
2426
var prop *PropertyEntry
2527
for i := range e.props {
@@ -30,9 +32,6 @@ func (e *Entity) FindProperty(name string) *PropertyEntry {
3032
prop = &e.props[i]
3133
}
3234
}
33-
if prop == nil {
34-
panic(fmt.Sprintf("Could not find property with name %q", name))
35-
}
3635
return prop
3736
}
3837

sendtables/parser.go

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,33 @@ import (
1111
msg "github.com/markus-wa/demoinfocs-golang/msg"
1212
)
1313

14-
// Parser provides functions for parsing send-tables.
15-
type Parser struct {
14+
// SendTableParser provides functions for parsing send-tables.
15+
type SendTableParser struct {
1616
sendTables []sendTable
1717
serverClasses []*ServerClass
1818
currentExcludes []*excludeEntry
1919
currentBaseclasses []*ServerClass
2020
}
2121

22+
type excludeEntry struct {
23+
varName string
24+
dtName string
25+
excludingDt string
26+
}
27+
2228
// ClassBits seems to calculate how many bits must be read for the server-class ID.
2329
// Not 100% sure how tho tbh.
24-
func (p *Parser) ClassBits() int {
30+
func (p *SendTableParser) ClassBits() int {
2531
return int(math.Ceil(math.Log2(float64(len(p.serverClasses)))))
2632
}
2733

2834
// ServerClasses returns the parsed server-classes
29-
func (p *Parser) ServerClasses() []*ServerClass {
35+
func (p *SendTableParser) ServerClasses() []*ServerClass {
3036
return p.serverClasses
3137
}
3238

3339
// ParsePacket parses a send-table packet.
34-
func (p *Parser) ParsePacket(r *bit.BitReader) {
40+
func (p *SendTableParser) ParsePacket(r *bit.BitReader) {
3541
for {
3642
t := msg.SVC_Messages(r.ReadVarInt32())
3743
if t != msg.SVC_Messages_svc_SendTable {
@@ -101,7 +107,7 @@ func parseSendTable(r *bit.BitReader) sendTable {
101107
return res
102108
}
103109

104-
func (p *Parser) flattenDataTable(serverClassIndex int) {
110+
func (p *SendTableParser) flattenDataTable(serverClassIndex int) {
105111
tab := &p.sendTables[p.serverClasses[serverClassIndex].DataTableID]
106112

107113
p.currentExcludes = nil
@@ -150,7 +156,7 @@ func (p *Parser) flattenDataTable(serverClassIndex int) {
150156
}
151157
}
152158

153-
func (p *Parser) gatherExcludesAndBaseClasses(st *sendTable, collectBaseClasses bool) {
159+
func (p *SendTableParser) gatherExcludesAndBaseClasses(st *sendTable, collectBaseClasses bool) {
154160
for _, v := range st.properties {
155161
if v.flags.hasFlagSet(propFlagExclude) {
156162
p.currentExcludes = append(p.currentExcludes, &excludeEntry{varName: v.name, dtName: v.dataTableName, excludingDt: st.name})
@@ -169,13 +175,13 @@ func (p *Parser) gatherExcludesAndBaseClasses(st *sendTable, collectBaseClasses
169175
}
170176
}
171177

172-
func (p *Parser) gatherProps(st *sendTable, serverClassIndex int, prefix string) {
178+
func (p *SendTableParser) gatherProps(st *sendTable, serverClassIndex int, prefix string) {
173179
var tmpFlattenedProps []FlattenedPropEntry
174180
p.gatherPropsIterate(st, serverClassIndex, prefix, &tmpFlattenedProps)
175181
p.serverClasses[serverClassIndex].FlattenedProps = append(p.serverClasses[serverClassIndex].FlattenedProps, tmpFlattenedProps...)
176182
}
177183

178-
func (p *Parser) gatherPropsIterate(tab *sendTable, serverClassIndex int, prefix string, flattenedProps *[]FlattenedPropEntry) {
184+
func (p *SendTableParser) gatherPropsIterate(tab *sendTable, serverClassIndex int, prefix string, flattenedProps *[]FlattenedPropEntry) {
179185
for i := range tab.properties {
180186
prop := &tab.properties[i]
181187
if prop.flags.hasFlagSet(propFlagInsideArray) || prop.flags.hasFlagSet(propFlagExclude) || p.isPropertyExcluded(tab, prop) {
@@ -204,7 +210,7 @@ func (p *Parser) gatherPropsIterate(tab *sendTable, serverClassIndex int, prefix
204210
}
205211
}
206212

207-
func (p *Parser) isPropertyExcluded(tab *sendTable, prop *sendTableProperty) bool {
213+
func (p *SendTableParser) isPropertyExcluded(tab *sendTable, prop *sendTableProperty) bool {
208214
for _, v := range p.currentExcludes {
209215
if v.dtName == tab.name && v.varName == prop.name {
210216
return true
@@ -213,7 +219,7 @@ func (p *Parser) isPropertyExcluded(tab *sendTable, prop *sendTableProperty) boo
213219
return false
214220
}
215221

216-
func (p *Parser) getTableByName(name string) *sendTable {
222+
func (p *SendTableParser) getTableByName(name string) *sendTable {
217223
for i := range p.sendTables {
218224
if p.sendTables[i].name == name {
219225
return &p.sendTables[i]
@@ -222,7 +228,7 @@ func (p *Parser) getTableByName(name string) *sendTable {
222228
return nil
223229
}
224230

225-
func (p *Parser) findServerClassByDtName(name string) *ServerClass {
231+
func (p *SendTableParser) findServerClassByDtName(name string) *ServerClass {
226232
var sc *ServerClass
227233
for _, v := range p.serverClasses {
228234
if v.DTName == name {
@@ -232,14 +238,13 @@ func (p *Parser) findServerClassByDtName(name string) *ServerClass {
232238
sc = v
233239
}
234240
}
235-
if sc == nil {
236-
panic(fmt.Sprintf("No server class with DT name %q found", name))
237-
}
238241
return sc
239242
}
240243

241244
// FindServerClassByName finds and returns a server-class by it's name.
242-
func (p *Parser) FindServerClassByName(name string) *ServerClass {
245+
// Returns nil if the server-class wasn't found.
246+
// Panics if more than one server-class with the same name was found.
247+
func (p *SendTableParser) FindServerClassByName(name string) *ServerClass {
243248
var sc *ServerClass
244249
for _, v := range p.serverClasses {
245250
if v.Name == name {
@@ -249,8 +254,5 @@ func (p *Parser) FindServerClassByName(name string) *ServerClass {
249254
sc = v
250255
}
251256
}
252-
if sc == nil {
253-
panic(fmt.Sprintf("No server class with name %q found", name))
254-
}
255257
return sc
256258
}

sendtables/propdecoder.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,17 @@ import (
99
bit "github.com/markus-wa/demoinfocs-golang/bitread"
1010
)
1111

12+
const (
13+
propTypeInt int = iota
14+
propTypeFloat
15+
propTypeVector
16+
propTypeVectorXY
17+
propTypeString
18+
propTypeArray
19+
propTypeDataTable
20+
propTypeInt64
21+
)
22+
1223
const (
1324
coordFractionalBitsMp = 5
1425
coordFractionalBitsMpLowPrecision = 3
@@ -26,6 +37,34 @@ const (
2637
normalResolution = 1.0 / normalDenominator
2738
)
2839

40+
const (
41+
dataTableMaxStringBits = 9
42+
dataTableMaxStringLength = 1 << dataTableMaxStringBits
43+
)
44+
45+
const (
46+
propFlagUnsigned sendPropertyFlags = (1 << iota)
47+
propFlagCoord
48+
propFlagNoScale
49+
propFlagRoundDown
50+
propFlagRoundUp
51+
propFlagNormal
52+
propFlagExclude
53+
propFlagXYZE
54+
propFlagInsideArray
55+
propFlagProxyAlwaysYes
56+
propFlagIsVectorElement
57+
propFlagCollapsible
58+
propFlagCoordMp
59+
propFlagCoordMpLowPrecision
60+
propFlagCoordMpIntegral
61+
propFlagCellCoord
62+
propFlagCellCoordLowPrecision
63+
propFlagCellCoordIntegral
64+
propFlagChangesOften
65+
propFlagVarInt
66+
)
67+
2968
const specialFloatFlags = propFlagNoScale | propFlagCoord | propFlagCellCoord | propFlagNormal | propFlagCoordMp | propFlagCoordMpLowPrecision | propFlagCoordMpIntegral | propFlagCellCoordLowPrecision | propFlagCellCoordIntegral
3069

3170
var propDecoder propertyDecoder

sendtables/sendtable.go

Lines changed: 0 additions & 20 deletions
This file was deleted.

sendtables/serverclass.go renamed to sendtables/sendtables.go

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,32 @@
1+
// Package sendtables contains sendtable specific magic and should really be better documented (TODO).
12
package sendtables
23

4+
// sendPropertyFlags stores multiple send property flags.
5+
type sendPropertyFlags int
6+
7+
// hasFlagSet returns true if the given flag is set
8+
func (spf sendPropertyFlags) hasFlagSet(flag sendPropertyFlags) bool {
9+
return int(spf)&int(flag) == int(flag)
10+
}
11+
12+
type sendTable struct {
13+
properties []sendTableProperty
14+
name string
15+
isEnd bool
16+
}
17+
18+
type sendTableProperty struct {
19+
flags sendPropertyFlags
20+
name string
21+
dataTableName string
22+
lowValue float32
23+
highValue float32
24+
numberOfBits int
25+
numberOfElements int
26+
priority int
27+
rawType int
28+
}
29+
330
// ServerClass stores meta information about Entity types (e.g. palyers, teams etc.).
431
type ServerClass struct {
532
ClassID int
@@ -39,12 +66,6 @@ func (fpe FlattenedPropEntry) Name() string {
3966
return fpe.name
4067
}
4168

42-
type excludeEntry struct {
43-
varName string
44-
dtName string
45-
excludingDt string
46-
}
47-
4869
// EntityCreatedEvent contains information about a newly created entity.
4970
type EntityCreatedEvent struct {
5071
ServerClass *ServerClass

0 commit comments

Comments
 (0)