Skip to content

Commit a1a9896

Browse files
committed
Allow parsing of additional net-messages
1 parent 5ac85be commit a1a9896

File tree

3 files changed

+78
-30
lines changed

3 files changed

+78
-30
lines changed

demoinfocs_test.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,13 @@ import (
1111
"testing"
1212
"time"
1313

14-
"github.com/markus-wa/godispatch"
14+
proto "github.com/gogo/protobuf/proto"
15+
dispatch "github.com/markus-wa/godispatch"
1516

1617
dem "github.com/markus-wa/demoinfocs-golang"
1718
common "github.com/markus-wa/demoinfocs-golang/common"
1819
events "github.com/markus-wa/demoinfocs-golang/events"
20+
msg "github.com/markus-wa/demoinfocs-golang/msg"
1921
)
2022

2123
const csDemosPath = "test/cs-demos"
@@ -38,6 +40,9 @@ func TestDemoInfoCs(t *testing.T) {
3840

3941
p := dem.NewParserWithConfig(f, dem.ParserConfig{
4042
MsgQueueBufferSize: 1000,
43+
AdditionalNetMessageCreators: map[int]dem.NetMessageCreator{
44+
4: func() proto.Message { return new(msg.CNETMsg_Tick) },
45+
},
4146
})
4247

4348
fmt.Println("Parsing header")
@@ -98,6 +103,13 @@ func TestDemoInfoCs(t *testing.T) {
98103
}
99104
})
100105

106+
// Net-message stuff
107+
var netTickHandlerID dispatch.HandlerIdentifier
108+
netTickHandlerID = p.RegisterNetMessageHandler(func(tick *msg.CNETMsg_Tick) {
109+
fmt.Println("Net-message tick handled, unregistering - tick:", tick.Tick)
110+
p.UnregisterNetMessageHandler(netTickHandlerID)
111+
})
112+
101113
ts := time.Now()
102114
var done int64
103115
go func() {

demopacket.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,14 @@ func (p *Parser) parsePacket() {
6565
debugUnhandledMessage(cmd, name)
6666
}
6767

68-
if name == "" {
68+
if name != "" {
69+
// Handle additional net-messages as defined by the user
70+
creator := p.additionalNetMessageCreators[cmd]
71+
if creator != nil {
72+
m = creator()
73+
break
74+
}
75+
} else {
6976
// Send a warning if the command is unknown
7077
// This might mean our proto files are out of date
7178
p.eventDispatcher.Dispatch(events.ParserWarnEvent{Message: fmt.Sprintf("Unknown message command %q", cmd)})
@@ -94,6 +101,10 @@ func (p *Parser) parsePacket() {
94101
p.bitReader.EndChunk()
95102
}
96103

104+
// NetMessageCreator creates additional net-messages to be dispatched to net-message handlers.
105+
// See also: ParserConfig.AdditionalNetMessageCreators & Parser.RegisterNetMessageHandler()
106+
type NetMessageCreator func() proto.Message
107+
97108
/*
98109
Format of 'CommandInfos' - I honestly have no clue what they are good for.
99110
If you find a use for this please let me know!

parser.go

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,32 @@ import (
1919
// After parsing the header Parser.ParseNextFrame() and Parser.ParseToEnd() can be used to parse the demo.
2020
// Use Parser.RegisterEventHandler() to receive notifications about events.
2121
type Parser struct {
22-
bitReader *bit.BitReader
23-
stParser st.SendTableParser
24-
msgDispatcher dp.Dispatcher
25-
eventDispatcher dp.Dispatcher
26-
msgQueue chan interface{}
27-
gameState GameState
28-
currentFrame int
29-
bombsiteA bombsite
30-
bombsiteB bombsite
31-
header *common.DemoHeader // Pointer so we can check for nil
32-
equipmentMapping map[*st.ServerClass]common.EquipmentElement
33-
rawPlayers map[int]*playerInfo
34-
entityIDToPlayers map[int]*common.Player // Temporary storage since we need to map players from entityID to userID later
35-
additionalPlayerInfo [maxPlayers]common.AdditionalPlayerInformation
36-
entities map[int]*st.Entity
37-
modelPreCache []string // Used to find out whether a weapon is a p250 or cz for example (same id)
38-
weapons [maxEntities]common.Equipment // Used to remember what a weapon is (p250 / cz etc.)
39-
triggers map[int]*boundingBoxInformation
40-
instanceBaselines map[int][]byte
41-
preprocessedBaselines map[int]map[int]st.PropValue
42-
gameEventDescs map[int32]*msg.CSVCMsg_GameEventListDescriptorT
43-
stringTables []*msg.CSVCMsg_CreateStringTable
44-
cancelChan chan struct{}
45-
err error
46-
errLock sync.Mutex
22+
bitReader *bit.BitReader
23+
stParser st.SendTableParser
24+
msgDispatcher dp.Dispatcher
25+
additionalNetMessageCreators map[int]NetMessageCreator
26+
eventDispatcher dp.Dispatcher
27+
msgQueue chan interface{}
28+
gameState GameState
29+
currentFrame int
30+
bombsiteA bombsite
31+
bombsiteB bombsite
32+
header *common.DemoHeader // Pointer so we can check for nil
33+
equipmentMapping map[*st.ServerClass]common.EquipmentElement
34+
rawPlayers map[int]*playerInfo
35+
entityIDToPlayers map[int]*common.Player // Temporary storage since we need to map players from entityID to userID later
36+
additionalPlayerInfo [maxPlayers]common.AdditionalPlayerInformation
37+
entities map[int]*st.Entity
38+
modelPreCache []string // Used to find out whether a weapon is a p250 or cz for example (same id)
39+
weapons [maxEntities]common.Equipment // Used to remember what a weapon is (p250 / cz etc.)
40+
triggers map[int]*boundingBoxInformation
41+
instanceBaselines map[int][]byte
42+
preprocessedBaselines map[int]map[int]st.PropValue
43+
gameEventDescs map[int32]*msg.CSVCMsg_GameEventListDescriptorT
44+
stringTables []*msg.CSVCMsg_CreateStringTable
45+
cancelChan chan struct{}
46+
err error
47+
errLock sync.Mutex
4748
}
4849

4950
type bombsite struct {
@@ -100,17 +101,33 @@ func (p *Parser) Progress() float32 {
100101
// Must be of type func(<EventType>) where EventType is the kind of event that is handled.
101102
// To catch all events func(interface{}) can be used.
102103
// Parameter handler has to be of type interface{} because lolnogenerics.
103-
// Returns a identifier with which the handler can be removed via UnregisterEventHandler()
104+
// Returns a identifier with which the handler can be removed via UnregisterEventHandler().
104105
func (p *Parser) RegisterEventHandler(handler interface{}) dp.HandlerIdentifier {
105106
return p.eventDispatcher.RegisterHandler(handler)
106107
}
107108

108-
// UnregisterEventHandler removes a handler via identifier.
109-
// The identifier is returned at registration by RegisterEventHandler()
109+
// UnregisterEventHandler removes a game event handler via identifier.
110+
// The identifier is returned at registration by RegisterEventHandler().
110111
func (p *Parser) UnregisterEventHandler(identifier dp.HandlerIdentifier) {
111112
p.eventDispatcher.UnregisterHandler(identifier)
112113
}
113114

115+
// RegisterNetMessageHandler registers a handler for net-messages.
116+
// Must be of type func(*<EventType>) where EventType is the kind of event that is handled.
117+
// To catch all events func(interface{}) can be used.
118+
// Parameter handler has to be of type interface{} because lolnogenerics.
119+
// Returns a identifier with which the handler can be removed via UnregisterNetMessageHandler().
120+
// This is a beta feature and may be changed or replaced without notice.
121+
func (p *Parser) RegisterNetMessageHandler(handler interface{}) dp.HandlerIdentifier {
122+
return p.msgDispatcher.RegisterHandler(handler)
123+
}
124+
125+
// UnregisterNetMessageHandler removes a net-message handler via identifier.
126+
// The identifier is returned at registration by RegisterNetMessageHandler().
127+
func (p *Parser) UnregisterNetMessageHandler(identifier dp.HandlerIdentifier) {
128+
p.msgDispatcher.UnregisterHandler(identifier)
129+
}
130+
114131
func (p *Parser) error() (err error) {
115132
p.errLock.Lock()
116133
err = p.err
@@ -143,6 +160,12 @@ type ParserConfig struct {
143160
// this is the default behavior for DefaultParserConfig.
144161
// Zero enforces sequential parsing.
145162
MsgQueueBufferSize int
163+
// AdditionalNetMessageCreators maps net-message-IDs to creators (instantiators).
164+
// The creators should return a new instance of the correct protobuf-message type (from the msg package).
165+
// Interesting net-message-IDs can easily be discovered with the build-tag 'debugdemoinfocs'; when looking for 'UnhandledMessage'.
166+
// Check out demopacket.go to see which net-messages are already being parsed by default.
167+
// This is a beta feature and may be changed or replaced without notice.
168+
AdditionalNetMessageCreators map[int]NetMessageCreator
146169
}
147170

148171
// DefaultParserConfig is the default Parser configuration used by NewParser().
@@ -182,6 +205,8 @@ func NewParserWithConfig(demostream io.Reader, config ParserConfig) *Parser {
182205
p.initMsgQueue(config.MsgQueueBufferSize)
183206
}
184207

208+
p.additionalNetMessageCreators = config.AdditionalNetMessageCreators
209+
185210
return &p
186211
}
187212

0 commit comments

Comments
 (0)