Skip to content

Commit 1f5745e

Browse files
committed
parsing: move code from demopacket.go to parsing.go
1 parent a0574a2 commit 1f5745e

File tree

3 files changed

+156
-161
lines changed

3 files changed

+156
-161
lines changed

demopacket.go

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

parser.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import (
55
"sync"
66
"time"
77

8-
r3 "github.com/golang/geo/r3"
8+
"github.com/gogo/protobuf/proto"
9+
"github.com/golang/geo/r3"
910
dp "github.com/markus-wa/godispatch"
1011

1112
bit "github.com/markus-wa/demoinfocs-golang/bitread"
12-
common "github.com/markus-wa/demoinfocs-golang/common"
13-
msg "github.com/markus-wa/demoinfocs-golang/msg"
13+
"github.com/markus-wa/demoinfocs-golang/common"
14+
"github.com/markus-wa/demoinfocs-golang/msg"
1415
st "github.com/markus-wa/demoinfocs-golang/sendtables"
1516
)
1617

@@ -73,6 +74,11 @@ type Parser struct {
7374
delayedEvents []interface{} // Contains events that need to be dispatched at the end of a tick (e.g. flash events because FlashDuration isn't updated before that)
7475
}
7576

77+
// NetMessageCreator creates additional net-messages to be dispatched to net-message handlers.
78+
//
79+
// See also: ParserConfig.AdditionalNetMessageCreators & Parser.RegisterNetMessageHandler()
80+
type NetMessageCreator func() proto.Message
81+
7682
type bombsite struct {
7783
index int
7884
center r3.Vector
@@ -210,7 +216,7 @@ type ParserConfig struct {
210216
// AdditionalNetMessageCreators maps net-message-IDs to creators (instantiators).
211217
// The creators should return a new instance of the correct protobuf-message type (from the msg package).
212218
// Interesting net-message-IDs can easily be discovered with the build-tag 'debugdemoinfocs'; when looking for 'UnhandledMessage'.
213-
// Check out demopacket.go to see which net-messages are already being parsed by default.
219+
// Check out parsing.go to see which net-messages are already being parsed by default.
214220
// This is a beta feature and may be changed or replaced without notice.
215221
AdditionalNetMessageCreators map[int]NetMessageCreator
216222
}

parsing.go

Lines changed: 146 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,14 @@ import (
44
"errors"
55
"fmt"
66
"io"
7+
"sync"
78
"time"
89

9-
common "github.com/markus-wa/demoinfocs-golang/common"
10-
events "github.com/markus-wa/demoinfocs-golang/events"
10+
"github.com/gogo/protobuf/proto"
11+
12+
"github.com/markus-wa/demoinfocs-golang/common"
13+
"github.com/markus-wa/demoinfocs-golang/events"
14+
"github.com/markus-wa/demoinfocs-golang/msg"
1115
)
1216

1317
const maxOsPath = 260
@@ -240,6 +244,97 @@ func (p *Parser) parseFrame() bool {
240244
return true
241245
}
242246

247+
var byteSlicePool = sync.Pool{
248+
New: func() interface{} {
249+
s := make([]byte, 0, 256)
250+
return &s
251+
},
252+
}
253+
254+
func (p *Parser) parsePacket() {
255+
// Booooring
256+
// 152 bytes CommandInfo, 4 bytes SeqNrIn, 4 bytes SeqNrOut
257+
// See at the bottom of the file what the CommandInfo would contain if you are interested.
258+
p.bitReader.Skip((152 + 4 + 4) << 3)
259+
260+
// Here we go
261+
p.bitReader.BeginChunk(p.bitReader.ReadSignedInt(32) << 3)
262+
for !p.bitReader.ChunkFinished() {
263+
cmd := int(p.bitReader.ReadVarInt32())
264+
size := int(p.bitReader.ReadVarInt32())
265+
266+
p.bitReader.BeginChunk(size << 3)
267+
var m proto.Message
268+
switch cmd {
269+
case int(msg.SVC_Messages_svc_PacketEntities):
270+
// We could pool CSVCMsg_PacketEntities as they take up A LOT of the allocations
271+
// but unless we're on a system that's doing a lot of concurrent parsing there isn't really a point
272+
// as handling packets is a lot slower than creating them and we can't pool until they are handled.
273+
m = new(msg.CSVCMsg_PacketEntities)
274+
275+
case int(msg.SVC_Messages_svc_GameEventList):
276+
m = new(msg.CSVCMsg_GameEventList)
277+
278+
case int(msg.SVC_Messages_svc_GameEvent):
279+
m = new(msg.CSVCMsg_GameEvent)
280+
281+
case int(msg.SVC_Messages_svc_CreateStringTable):
282+
m = new(msg.CSVCMsg_CreateStringTable)
283+
284+
case int(msg.SVC_Messages_svc_UpdateStringTable):
285+
m = new(msg.CSVCMsg_UpdateStringTable)
286+
287+
case int(msg.SVC_Messages_svc_UserMessage):
288+
m = new(msg.CSVCMsg_UserMessage)
289+
290+
default:
291+
var name string
292+
if cmd < 8 || cmd >= 100 {
293+
name = msg.NET_Messages_name[int32(cmd)]
294+
} else {
295+
name = msg.SVC_Messages_name[int32(cmd)]
296+
}
297+
298+
if isDebug {
299+
debugUnhandledMessage(cmd, name)
300+
}
301+
302+
if name != "" {
303+
// Handle additional net-messages as defined by the user
304+
creator := p.additionalNetMessageCreators[cmd]
305+
if creator != nil {
306+
m = creator()
307+
break
308+
}
309+
} else {
310+
// Send a warning if the command is unknown
311+
// This might mean our proto files are out of date
312+
p.eventDispatcher.Dispatch(events.ParserWarn{Message: fmt.Sprintf("Unknown message command %q", cmd)})
313+
}
314+
315+
// On to the next one
316+
p.bitReader.EndChunk()
317+
continue
318+
}
319+
320+
b := byteSlicePool.Get().(*[]byte)
321+
p.bitReader.ReadBytesInto(b, size)
322+
323+
if proto.Unmarshal(*b, m) != nil {
324+
// TODO: Don't crash here, happens with demos that work in gotv
325+
panic(fmt.Sprintf("Failed to unmarshal cmd %d", cmd))
326+
}
327+
p.msgQueue <- m
328+
329+
// Reset length to 0 and pool
330+
*b = (*b)[:0]
331+
byteSlicePool.Put(b)
332+
333+
p.bitReader.EndChunk()
334+
}
335+
p.bitReader.EndChunk()
336+
}
337+
243338
type frameParsedTokenType struct{}
244339

245340
var frameParsedToken = new(frameParsedTokenType)
@@ -255,3 +350,52 @@ func (p *Parser) handleFrameParsed(*frameParsedTokenType) {
255350
p.currentFrame++
256351
p.eventDispatcher.Dispatch(events.TickDone{})
257352
}
353+
354+
/*
355+
Format of 'CommandInfos' - I honestly have no clue what they are good for.
356+
This data is skipped in Parser.parsePacket().
357+
If you find a use for this please let me know!
358+
359+
Here is all i know:
360+
361+
CommandInfo [152 bytes]
362+
- [2]Split
363+
364+
Split [76 bytes]
365+
- flags [4 bytes]
366+
- viewOrigin [12 bytes]
367+
- viewAngles [12 bytes]
368+
- localViewAngles [12 bytes]
369+
- viewOrigin2 [12 bytes]
370+
- viewAngles2 [12 bytes]
371+
- localViewAngles2 [12 bytes]
372+
373+
Origin [12 bytes]
374+
- X [4 bytes]
375+
- Y [4 bytes]
376+
- Z [4 bytes]
377+
378+
Angle [12 bytes]
379+
- X [4 bytes]
380+
- Y [4 bytes]
381+
- Z [4 bytes]
382+
383+
They are parsed in the following order:
384+
split1.flags
385+
split1.viewOrigin.x
386+
split1.viewOrigin.y
387+
split1.viewOrigin.z
388+
split1.viewAngles.x
389+
split1.viewAngles.y
390+
split1.viewAngles.z
391+
split1.localViewAngles.x
392+
split1.localViewAngles.y
393+
split1.localViewAngles.z
394+
split1.viewOrigin2...
395+
split1.viewAngles2...
396+
split1.localViewAngles2...
397+
split2.flags
398+
...
399+
400+
Or just check this file's history for an example on how to parse them
401+
*/

0 commit comments

Comments
 (0)