diff options
Diffstat (limited to 'demo')
36 files changed, 1423 insertions, 0 deletions
diff --git a/demo/dem/data.go b/demo/dem/data.go new file mode 100644 index 0000000..87ff90a --- /dev/null +++ b/demo/dem/data.go @@ -0,0 +1,54 @@ +package dem + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/packet" + "github.com/osm/quake/packet/svc" +) + +type Data struct { + Size uint32 + Angle [3]float32 + Packet packet.Packet +} + +func (d *Data) Bytes() []byte { + buf := buffer.New() + + buf.PutUint32(d.Size) + + for i := 0; i < 3; i++ { + buf.PutFloat32(d.Angle[i]) + } + + buf.PutBytes(d.Packet.Bytes()) + + return buf.Bytes() +} + +func parseData(ctx *context.Context, buf *buffer.Buffer) (*Data, error) { + var err error + var data Data + + if data.Size, err = buf.GetUint32(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if data.Angle[i], err = buf.GetFloat32(); err != nil { + return nil, err + } + } + + bytes, err := buf.GetBytes(int(data.Size)) + if err != nil { + return nil, err + } + + if data.Packet, err = svc.Parse(ctx, bytes); err != nil { + return nil, err + } + + return &data, nil +} diff --git a/demo/dem/parse.go b/demo/dem/parse.go new file mode 100644 index 0000000..203a711 --- /dev/null +++ b/demo/dem/parse.go @@ -0,0 +1,57 @@ +package dem + +import ( + "errors" + + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +var ErrUnknownType = errors.New("unknown type") + +type Demo struct { + CDTrack []byte + Data []*Data +} + +func (dem *Demo) Bytes() []byte { + buf := buffer.New() + + buf.PutBytes(dem.CDTrack) + + for _, d := range dem.Data { + buf.PutBytes(d.Bytes()) + } + + return buf.Bytes() +} + +func Parse(ctx *context.Context, data []byte) (*Demo, error) { + var demo Demo + + buf := buffer.New(buffer.WithData(data)) + ctx.SetIsDem(true) + + for buf.Off() < buf.Len() { + b, err := buf.ReadByte() + if err != nil { + return nil, err + } + + demo.CDTrack = append(demo.CDTrack, b) + if b == '\n' { + break + } + } + + for buf.Off() < buf.Len() { + d, err := parseData(ctx, buf) + if err != nil { + return nil, err + } + + demo.Data = append(demo.Data, d) + } + + return &demo, nil +} diff --git a/demo/dem/parse_test.go b/demo/dem/parse_test.go new file mode 100644 index 0000000..d3d33cf --- /dev/null +++ b/demo/dem/parse_test.go @@ -0,0 +1,55 @@ +package dem + +import ( + "crypto/sha256" + "fmt" + "io/ioutil" + "testing" + + "github.com/osm/quake/common/context" +) + +type demTest struct { + filePath string + checksum string +} + +var demTests = []demTest{ + { + filePath: "testdata/demo1.dem", + checksum: "893e5279e3a84fed0416a1101dfc2b6bca1ebd28787323daa8e22cefe54883c1", + }, + { + filePath: "testdata/demo2.dem", + checksum: "150e6fc54c24a70a44012ba71473a5cbbec081e19204a9eae98249621fef00d7", + }, + { + filePath: "testdata/demo3.dem", + checksum: "7bee6edc47fe563cbf8f1e873d524d1e4cef7d919b523606e200c0d7c269bd83", + }, +} + +func TestParse(t *testing.T) { + for _, dt := range demTests { + t.Run(dt.filePath, func(t *testing.T) { + data, err := ioutil.ReadFile(dt.filePath) + if err != nil { + t.Errorf("unable to open demo file, %v", err) + } + + demo, err := Parse(context.New(), data) + if err != nil { + t.Errorf("unable to parse demo, %v", err) + } + + h := sha256.New() + h.Write(demo.Bytes()) + checksum := fmt.Sprintf("%x", h.Sum(nil)) + if checksum != dt.checksum { + t.Errorf("sha256 checksums didn't match") + t.Logf("output: %#v", checksum) + t.Logf("expected: %#v", dt.checksum) + } + }) + } +} diff --git a/demo/dem/testdata/demo1.dem b/demo/dem/testdata/demo1.dem Binary files differnew file mode 100644 index 0000000..2b821c3 --- /dev/null +++ b/demo/dem/testdata/demo1.dem diff --git a/demo/dem/testdata/demo2.dem b/demo/dem/testdata/demo2.dem Binary files differnew file mode 100644 index 0000000..9dd006e --- /dev/null +++ b/demo/dem/testdata/demo2.dem diff --git a/demo/dem/testdata/demo3.dem b/demo/dem/testdata/demo3.dem Binary files differnew file mode 100644 index 0000000..d25c402 --- /dev/null +++ b/demo/dem/testdata/demo3.dem diff --git a/demo/mvd/cmd.go b/demo/mvd/cmd.go new file mode 100644 index 0000000..d89f492 --- /dev/null +++ b/demo/mvd/cmd.go @@ -0,0 +1,93 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type Cmd struct { + Msec byte + UserAngle [3]float32 + Forward uint16 + Side uint16 + Up uint16 + Buttons byte + Impulse byte + Padding [3]byte + Angle [3]float32 +} + +func (cmd *Cmd) Bytes() []byte { + buf := buffer.New() + + buf.PutByte(cmd.Msec) + + for i := 0; i < 3; i++ { + buf.PutFloat32(cmd.UserAngle[i]) + } + + buf.PutUint16(cmd.Forward) + buf.PutUint16(cmd.Side) + buf.PutUint16(cmd.Up) + buf.PutByte(cmd.Buttons) + buf.PutByte(cmd.Impulse) + + for i := 0; i < 3; i++ { + buf.PutByte(cmd.Padding[i]) + } + + for i := 0; i < 3; i++ { + buf.PutFloat32(cmd.Angle[i]) + } + + return buf.Bytes() +} + +func parseCmd(ctx *context.Context, buf *buffer.Buffer) (*Cmd, error) { + var err error + var cmd Cmd + + if cmd.Msec, err = buf.ReadByte(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if cmd.UserAngle[i], err = buf.GetFloat32(); err != nil { + return nil, err + } + } + + if cmd.Forward, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Side, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Up, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Buttons, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Impulse, err = buf.ReadByte(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if cmd.Padding[i], err = buf.ReadByte(); err != nil { + return nil, err + } + } + + for i := 0; i < 3; i++ { + if cmd.Angle[i], err = buf.GetFloat32(); err != nil { + return nil, err + } + } + + return &cmd, nil +} diff --git a/demo/mvd/damagedone.go b/demo/mvd/damagedone.go new file mode 100644 index 0000000..cf9012a --- /dev/null +++ b/demo/mvd/damagedone.go @@ -0,0 +1,63 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type DamageDone struct { + size uint32 + + Data []byte + DeathType uint16 + AttackerEnt uint16 + TargetEnt uint16 + Damage uint16 +} + +func (cmd *DamageDone) Bytes() []byte { + if cmd.size != 8 { + return cmd.Data + } + + buf := buffer.New() + buf.PutUint16(cmd.DeathType) + buf.PutUint16(cmd.AttackerEnt) + buf.PutUint16(cmd.TargetEnt) + buf.PutUint16(cmd.Damage) + + return buf.Bytes() +} + +func parseDamageDone(ctx *context.Context, buf *buffer.Buffer, size uint32) (*DamageDone, error) { + var err error + var cmd DamageDone + + cmd.size = size + if cmd.size != 8 { + if cmd.Data, err = buf.GetBytes(int(cmd.size)); err != nil { + return nil, err + } + + goto end + } + + if cmd.DeathType, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.AttackerEnt, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.TargetEnt, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Damage, err = buf.GetUint16(); err != nil { + return nil, err + } + +end: + return &cmd, nil +} diff --git a/demo/mvd/demoinfo.go b/demo/mvd/demoinfo.go new file mode 100644 index 0000000..c52a645 --- /dev/null +++ b/demo/mvd/demoinfo.go @@ -0,0 +1,35 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type DemoInfo struct { + BlockNumber uint16 + Data []byte +} + +func (cmd *DemoInfo) Bytes() []byte { + buf := buffer.New() + + buf.PutUint16(cmd.BlockNumber) + buf.PutBytes(cmd.Data) + + return buf.Bytes() +} + +func parseDemoInfo(ctx *context.Context, buf *buffer.Buffer, size uint32) (*DemoInfo, error) { + var err error + var cmd DemoInfo + + if cmd.BlockNumber, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Data, err = buf.GetBytes(int(size) - 2); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/mvd/hidden.go b/demo/mvd/hidden.go new file mode 100644 index 0000000..f9b5ebf --- /dev/null +++ b/demo/mvd/hidden.go @@ -0,0 +1,71 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/packet/command" + "github.com/osm/quake/protocol" + "github.com/osm/quake/protocol/mvd" +) + +type HiddenCommand struct { + Size uint32 + Type uint16 + Command command.Command +} + +func (cmd *HiddenCommand) Bytes() []byte { + buf := buffer.New() + + buf.PutUint32(cmd.Size) + buf.PutUint16(cmd.Type) + buf.PutBytes(cmd.Command.Bytes()) + + return buf.Bytes() +} + +func parseHiddenCommands(ctx *context.Context, data []byte) ([]*HiddenCommand, error) { + var err error + var cmds []*HiddenCommand + + buf := buffer.New(buffer.WithData(data)) + + for buf.Off() < buf.Len() { + var cmd HiddenCommand + + if cmd.Size, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.Type, err = buf.GetUint16(); err != nil { + return nil, err + } + + var c command.Command + switch protocol.CommandType(cmd.Type) { + case mvd.HiddenUserCommand: + c, err = parseUserCommand(ctx, buf, cmd.Size) + case mvd.HiddenUserCommandWeapon: + c, err = parseWeapon(ctx, buf, cmd.Size) + case mvd.HiddenDemoInfo: + c, err = parseDemoInfo(ctx, buf, cmd.Size) + case mvd.HiddenDamangeDone: + c, err = parseDamageDone(ctx, buf, cmd.Size) + case mvd.HiddenUserCommandWeaponServerSide: + c, err = parseWeaponServerSide(ctx, buf, cmd.Size) + case mvd.HiddenUserCommandWeaponInstruction: + c, err = parseWeaponInstruction(ctx, buf, cmd.Size) + default: + c, err = parseUnknown(ctx, buf, cmd.Size) + } + + if err != nil { + return cmds, err + } + cmd.Command = c + + cmds = append(cmds, &cmd) + } + + return cmds, nil +} diff --git a/demo/mvd/mutliple.go b/demo/mvd/mutliple.go new file mode 100644 index 0000000..6b66d37 --- /dev/null +++ b/demo/mvd/mutliple.go @@ -0,0 +1,58 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/protocol/mvd" +) + +type Multiple struct { + LastTo uint32 + IsHiddenPacket bool + Size uint32 + HiddenCommands []*HiddenCommand +} + +func (cmd *Multiple) Bytes() []byte { + buf := buffer.New() + + buf.PutUint32(cmd.LastTo) + + if cmd.IsHiddenPacket { + buf.PutUint32(cmd.Size) + + for _, c := range cmd.HiddenCommands { + buf.PutBytes(c.Bytes()) + } + } + + return buf.Bytes() +} + +func parseMultiple(ctx *context.Context, buf *buffer.Buffer) (*Multiple, error) { + var err error + var cmd Multiple + + if cmd.LastTo, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.LastTo == 0 && ctx.GetMVDProtocolExtension()&mvd.ExtensionHiddenMessages != 0 { + cmd.IsHiddenPacket = true + + if cmd.Size, err = buf.GetUint32(); err != nil { + return nil, err + } + + bytes, err := buf.GetBytes(int(cmd.Size)) + if err != nil { + return nil, err + } + + if cmd.HiddenCommands, err = parseHiddenCommands(ctx, bytes); err != nil { + return nil, err + } + } + + return &cmd, nil +} diff --git a/demo/mvd/parse.go b/demo/mvd/parse.go new file mode 100644 index 0000000..20ea811 --- /dev/null +++ b/demo/mvd/parse.go @@ -0,0 +1,133 @@ +package mvd + +import ( + "errors" + + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/protocol" + "github.com/osm/quake/protocol/mvd" +) + +var ErrUnknownType = errors.New("unknown type") + +type Demo struct { + Data []Data +} + +type Data struct { + Target uint32 + Timestamp byte + Command byte + Cmd *Cmd + Read *Read + Set *Set + Multiple *Multiple +} + +func (d *Demo) Bytes() []byte { + buf := buffer.New() + + for i := 0; i < len(d.Data); i++ { + buf.PutBytes(d.Data[i].Bytes()) + } + + return buf.Bytes() +} + +func (d *Data) Bytes() []byte { + buf := buffer.New() + + buf.PutByte(d.Timestamp) + buf.PutByte(d.Command) + + switch d.Command & 0x7 { + case mvd.DemoMultiple: + buf.PutBytes(d.Multiple.Bytes()) + fallthrough + case mvd.DemoStats: + fallthrough + case mvd.DemoSingle: + fallthrough + case mvd.DemoAll: + fallthrough + case protocol.DemoRead: + buf.PutBytes(d.Read.Bytes()) + case protocol.DemoSet: + buf.PutBytes(d.Set.Bytes()) + case protocol.DemoCmd: + buf.PutBytes(d.Cmd.Bytes()) + } + + return buf.Bytes() +} + +func Parse(ctx *context.Context, data []byte) (*Demo, error) { + var err error + var cmd Demo + + buf := buffer.New(buffer.WithData(data)) + ctx.SetIsMVD(true) + + for buf.Off() < buf.Len() { + var data Data + + process: + if data.Timestamp, err = buf.ReadByte(); err != nil { + return nil, err + } + + if data.Command, err = buf.ReadByte(); err != nil { + return nil, err + } + + switch data.Command & 0x7 { + case mvd.DemoMultiple: + if data.Multiple, err = parseMultiple(ctx, buf); err != nil { + return nil, err + } + data.Target = data.Multiple.LastTo + + if data.Multiple.IsHiddenPacket { + cmd.Data = append(cmd.Data, data) + + if buf.Off() == buf.Len() { + goto end + } + + goto process + } + + fallthrough + case mvd.DemoStats: + fallthrough + case mvd.DemoSingle: + // Target determines which client the data is intended + // to reach and can be used in conjunction with the + // updateuserinfo to determine who the client is. + data.Target = uint32(data.Command >> 3) + fallthrough + case mvd.DemoAll: + fallthrough + case protocol.DemoRead: + if data.Read, err = parseRead(ctx, buf); err != nil { + return nil, err + } + case protocol.DemoSet: + if data.Set, err = parseSet(ctx, buf); err != nil { + return nil, err + } + case protocol.DemoCmd: + if data.Cmd, err = parseCmd(ctx, buf); err != nil { + return nil, err + } + default: + return nil, ErrUnknownType + } + + cmd.Data = append(cmd.Data, data) + } + +end: + return &cmd, nil +} diff --git a/demo/mvd/parse_test.go b/demo/mvd/parse_test.go new file mode 100644 index 0000000..53a00a3 --- /dev/null +++ b/demo/mvd/parse_test.go @@ -0,0 +1,59 @@ +package mvd + +import ( + "crypto/sha256" + "fmt" + "io/ioutil" + "testing" + + "github.com/osm/quake/common/context" +) + +type mvdTest struct { + filePath string + checksum string +} + +var mvdTests = []mvdTest{ + { + filePath: "testdata/demo1.mvd", + checksum: "9489430c9513aed5b8e444df1b0d2040acb55de565c1b3e237dce51c8c103c57", + }, + { + filePath: "testdata/demo2.mvd", + checksum: "d40c3864dd3c052a8379e7e589cd045814ec462f6cf4432a2c94ec740843e30d", + }, + { + filePath: "testdata/demo3.mvd", + checksum: "3dd728aa90fdae100ade62d9b93220b7689f6ebdca6c986d3c2b1208b4e1e33c", + }, + { + filePath: "testdata/demo4.mvd", + checksum: "1f7b2c0ad77608f431028c8e68904400fe406150875a51f793f3395bf3784c90", + }, +} + +func TestParse(t *testing.T) { + for _, mt := range mvdTests { + t.Run(mt.filePath, func(t *testing.T) { + data, err := ioutil.ReadFile(mt.filePath) + if err != nil { + t.Errorf("unable to open demo file, %v", err) + } + + demo, err := Parse(context.New(), data) + if err != nil { + t.Errorf("unable to parse demo, %v", err) + } + + h := sha256.New() + h.Write(demo.Bytes()) + checksum := fmt.Sprintf("%x", h.Sum(nil)) + if checksum != mt.checksum { + t.Errorf("sha256 checksums didn't match") + t.Logf("output: %#v", checksum) + t.Logf("expected: %#v", mt.checksum) + } + }) + } +} diff --git a/demo/mvd/read.go b/demo/mvd/read.go new file mode 100644 index 0000000..20dae8a --- /dev/null +++ b/demo/mvd/read.go @@ -0,0 +1,46 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/packet" + "github.com/osm/quake/packet/svc" +) + +type Read struct { + Size uint32 + Packet packet.Packet +} + +func (cmd *Read) Bytes() []byte { + if cmd == nil || cmd.Packet == nil { + return []byte{} + } + + buf := buffer.New() + + buf.PutUint32(cmd.Size) + buf.PutBytes(cmd.Packet.Bytes()) + + return buf.Bytes() +} + +func parseRead(ctx *context.Context, buf *buffer.Buffer) (*Read, error) { + var err error + var cmd Read + + if cmd.Size, err = buf.GetUint32(); err != nil { + return nil, err + } + + bytes, err := buf.GetBytes(int(cmd.Size)) + if err != nil { + return nil, err + } + + if cmd.Packet, err = svc.Parse(ctx, bytes); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/mvd/set.go b/demo/mvd/set.go new file mode 100644 index 0000000..8cc4c95 --- /dev/null +++ b/demo/mvd/set.go @@ -0,0 +1,35 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type Set struct { + SeqOut uint32 + SeqIn uint32 +} + +func (cmd *Set) Bytes() []byte { + buf := buffer.New() + + buf.PutUint32(cmd.SeqOut) + buf.PutUint32(cmd.SeqIn) + + return buf.Bytes() +} + +func parseSet(ctx *context.Context, buf *buffer.Buffer) (*Set, error) { + var err error + var cmd Set + + if cmd.SeqOut, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.SeqIn, err = buf.GetUint32(); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/mvd/testdata/demo1.mvd b/demo/mvd/testdata/demo1.mvd Binary files differnew file mode 100644 index 0000000..052b266 --- /dev/null +++ b/demo/mvd/testdata/demo1.mvd diff --git a/demo/mvd/testdata/demo2.mvd b/demo/mvd/testdata/demo2.mvd Binary files differnew file mode 100644 index 0000000..c8f32e4 --- /dev/null +++ b/demo/mvd/testdata/demo2.mvd diff --git a/demo/mvd/testdata/demo3.mvd b/demo/mvd/testdata/demo3.mvd Binary files differnew file mode 100644 index 0000000..374af38 --- /dev/null +++ b/demo/mvd/testdata/demo3.mvd diff --git a/demo/mvd/testdata/demo4.mvd b/demo/mvd/testdata/demo4.mvd Binary files differnew file mode 100644 index 0000000..d2589ec --- /dev/null +++ b/demo/mvd/testdata/demo4.mvd diff --git a/demo/mvd/unknown.go b/demo/mvd/unknown.go new file mode 100644 index 0000000..ec0747a --- /dev/null +++ b/demo/mvd/unknown.go @@ -0,0 +1,25 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type Unknown struct { + Data []byte +} + +func (cmd *Unknown) Bytes() []byte { + return cmd.Data +} + +func parseUnknown(ctx *context.Context, buf *buffer.Buffer, size uint32) (*Unknown, error) { + var err error + var cmd Unknown + + if cmd.Data, err = buf.GetBytes(int(size)); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/mvd/usercommand.go b/demo/mvd/usercommand.go new file mode 100644 index 0000000..fc06b18 --- /dev/null +++ b/demo/mvd/usercommand.go @@ -0,0 +1,100 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type UserCommand struct { + size uint32 + + Data []byte + PlayerIndex byte + DropIndex byte + Msec byte + Angle [3]float32 + Forward uint16 + Side uint16 + Up uint16 + Buttons byte + Impulse byte +} + +func (cmd *UserCommand) Bytes() []byte { + if cmd.size != 23 { + return cmd.Data + } + + buf := buffer.New() + + buf.PutByte(cmd.PlayerIndex) + buf.PutByte(cmd.DropIndex) + buf.PutByte(cmd.Msec) + + for _, a := range cmd.Angle { + buf.PutFloat32(a) + } + + buf.PutUint16(cmd.Forward) + buf.PutUint16(cmd.Side) + buf.PutUint16(cmd.Up) + buf.PutByte(cmd.Buttons) + buf.PutByte(cmd.Impulse) + + return buf.Bytes() +} + +func parseUserCommand(ctx *context.Context, buf *buffer.Buffer, size uint32) (*UserCommand, error) { + var err error + var cmd UserCommand + + cmd.size = size + if cmd.size != 23 { + if cmd.Data, err = buf.GetBytes(int(cmd.size)); err != nil { + return nil, err + } + + goto end + } + + if cmd.PlayerIndex, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.DropIndex, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Msec, err = buf.ReadByte(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if cmd.Angle[i], err = buf.GetFloat32(); err != nil { + return nil, err + } + } + + if cmd.Forward, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Side, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Up, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Buttons, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Impulse, err = buf.ReadByte(); err != nil { + return nil, err + } + +end: + return &cmd, nil +} diff --git a/demo/mvd/weapon.go b/demo/mvd/weapon.go new file mode 100644 index 0000000..d7b6bf0 --- /dev/null +++ b/demo/mvd/weapon.go @@ -0,0 +1,71 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type Weapon struct { + PlayerIndex byte + Items uint32 + Shells byte + Nails byte + Rockets byte + Cells byte + Choice byte + String string +} + +func (cmd *Weapon) Bytes() []byte { + buf := buffer.New() + + buf.PutByte(cmd.PlayerIndex) + buf.PutUint32(cmd.Items) + buf.PutByte(cmd.Shells) + buf.PutByte(cmd.Nails) + buf.PutByte(cmd.Rockets) + buf.PutByte(cmd.Cells) + buf.PutByte(cmd.Choice) + buf.PutString(cmd.String) + + return buf.Bytes() +} + +func parseWeapon(ctx *context.Context, buf *buffer.Buffer, size uint32) (*Weapon, error) { + var err error + var cmd Weapon + + if cmd.PlayerIndex, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Items, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.Shells, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Nails, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Rockets, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Cells, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Choice, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.String, err = buf.GetString(); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/mvd/weaponinstruction.go b/demo/mvd/weaponinstruction.go new file mode 100644 index 0000000..d923d1b --- /dev/null +++ b/demo/mvd/weaponinstruction.go @@ -0,0 +1,57 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type WeaponInstruction struct { + PlayerIndex byte + Bits byte + Seq uint32 + Mode uint32 + WeaponList []byte +} + +func (cmd *WeaponInstruction) Bytes() []byte { + buf := buffer.New() + + buf.PutByte(cmd.PlayerIndex) + buf.PutByte(cmd.Bits) + buf.PutUint32(cmd.Seq) + buf.PutUint32(cmd.Mode) + buf.PutBytes(cmd.WeaponList) + + return buf.Bytes() +} + +func parseWeaponInstruction( + ctx *context.Context, + buf *buffer.Buffer, + size uint32, +) (*WeaponInstruction, error) { + var err error + var cmd WeaponInstruction + + if cmd.PlayerIndex, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Bits, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Seq, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.Mode, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.WeaponList, err = buf.GetBytes(10); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/mvd/weaponserverside.go b/demo/mvd/weaponserverside.go new file mode 100644 index 0000000..36840e9 --- /dev/null +++ b/demo/mvd/weaponserverside.go @@ -0,0 +1,75 @@ +package mvd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type WeaponServerSide struct { + PlayerIndex byte + Items uint32 + Shells byte + Nails byte + Rockets byte + Cells byte + Choice byte + String string +} + +func (cmd *WeaponServerSide) Bytes() []byte { + buf := buffer.New() + + buf.PutByte(cmd.PlayerIndex) + buf.PutUint32(cmd.Items) + buf.PutByte(cmd.Shells) + buf.PutByte(cmd.Nails) + buf.PutByte(cmd.Rockets) + buf.PutByte(cmd.Cells) + buf.PutByte(cmd.Choice) + buf.PutString(cmd.String) + + return buf.Bytes() +} + +func parseWeaponServerSide( + ctx *context.Context, + buf *buffer.Buffer, + size uint32, +) (*WeaponServerSide, error) { + var err error + var cmd WeaponServerSide + + if cmd.PlayerIndex, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Items, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.Shells, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Nails, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Rockets, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Cells, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Choice, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.String, err = buf.GetString(); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/qwd/cmd.go b/demo/qwd/cmd.go new file mode 100644 index 0000000..8bd4d15 --- /dev/null +++ b/demo/qwd/cmd.go @@ -0,0 +1,94 @@ +package qwd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type Cmd struct { + Msec byte + UserAngle [3]float32 + Forward uint16 + Side uint16 + Up uint16 + Buttons byte + Impulse byte + Padding [3]byte + Angle [3]float32 +} + +func (cmd *Cmd) Bytes() []byte { + buf := buffer.New() + + buf.PutByte(cmd.Msec) + + for i := 0; i < 3; i++ { + buf.PutFloat32(cmd.UserAngle[i]) + } + + buf.PutUint16(cmd.Forward) + buf.PutUint16(cmd.Side) + buf.PutUint16(cmd.Up) + + for i := 0; i < 3; i++ { + buf.PutByte(cmd.Padding[i]) + } + + buf.PutByte(cmd.Buttons) + buf.PutByte(cmd.Impulse) + + for i := 0; i < 3; i++ { + buf.PutFloat32(cmd.Angle[i]) + } + + return buf.Bytes() +} + +func parseCmd(ctx *context.Context, buf *buffer.Buffer) (*Cmd, error) { + var err error + var cmd Cmd + + if cmd.Msec, err = buf.ReadByte(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if cmd.UserAngle[i], err = buf.GetFloat32(); err != nil { + return nil, err + } + } + + if cmd.Forward, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Side, err = buf.GetUint16(); err != nil { + return nil, err + } + + if cmd.Up, err = buf.GetUint16(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if cmd.Padding[i], err = buf.ReadByte(); err != nil { + return nil, err + } + } + + if cmd.Buttons, err = buf.ReadByte(); err != nil { + return nil, err + } + + if cmd.Impulse, err = buf.ReadByte(); err != nil { + return nil, err + } + + for i := 0; i < 3; i++ { + if cmd.Angle[i], err = buf.GetFloat32(); err != nil { + return nil, err + } + } + + return &cmd, nil +} diff --git a/demo/qwd/data.go b/demo/qwd/data.go new file mode 100644 index 0000000..cc00c23 --- /dev/null +++ b/demo/qwd/data.go @@ -0,0 +1,32 @@ +package qwd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/protocol" +) + +type Data struct { + Timestamp float32 + Command byte + Cmd *Cmd + Read *Read + Set *Set +} + +func (d *Data) Bytes() []byte { + buf := buffer.New() + + buf.PutFloat32(d.Timestamp) + buf.PutByte(d.Command) + + switch d.Command { + case protocol.DemoCmd: + buf.PutBytes(d.Cmd.Bytes()) + case protocol.DemoRead: + buf.PutBytes(d.Read.Bytes()) + case protocol.DemoSet: + buf.PutBytes(d.Set.Bytes()) + } + + return buf.Bytes() +} diff --git a/demo/qwd/parse.go b/demo/qwd/parse.go new file mode 100644 index 0000000..458f714 --- /dev/null +++ b/demo/qwd/parse.go @@ -0,0 +1,66 @@ +package qwd + +import ( + "errors" + + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/protocol" +) + +var ErrUnknownType = errors.New("unknown type") + +type Demo struct { + Data []*Data +} + +func (dem *Demo) Bytes() []byte { + buf := buffer.New() + + for _, d := range dem.Data { + buf.PutBytes(d.Bytes()) + } + + return buf.Bytes() +} + +func Parse(ctx *context.Context, data []byte) (*Demo, error) { + var err error + var cmd Demo + + buf := buffer.New(buffer.WithData(data)) + ctx.SetIsQWD(true) + + for buf.Off() < buf.Len() { + var data Data + + if data.Timestamp, err = buf.GetFloat32(); err != nil { + return nil, err + } + + if data.Command, err = buf.ReadByte(); err != nil { + return nil, err + } + + switch data.Command { + case protocol.DemoCmd: + if data.Cmd, err = parseCmd(ctx, buf); err != nil { + return nil, err + } + case protocol.DemoRead: + if data.Read, err = parseRead(ctx, buf); err != nil { + return nil, err + } + case protocol.DemoSet: + if data.Set, err = parseSet(ctx, buf); err != nil { + return nil, err + } + default: + return nil, ErrUnknownType + } + + cmd.Data = append(cmd.Data, &data) + } + + return &cmd, nil +} diff --git a/demo/qwd/parse_test.go b/demo/qwd/parse_test.go new file mode 100644 index 0000000..97e39df --- /dev/null +++ b/demo/qwd/parse_test.go @@ -0,0 +1,67 @@ +package qwd + +import ( + "crypto/sha256" + "fmt" + "io/ioutil" + "testing" + + "github.com/osm/quake/common/context" +) + +type qwdTest struct { + filePath string + checksum string +} + +var qwdTests = []qwdTest{ + { + filePath: "testdata/demo1.qwd", + checksum: "849cf01cb3fe5c7161625dafdf03178536048d093eda885ca9b37fc673c3c72a", + }, + { + filePath: "testdata/demo2.qwd", + checksum: "c90f0a6c9ba79fc7f84d90b12d923a3ad2c0e54849d8df6fd913264f147931b2", + }, + { + filePath: "testdata/demo3.qwd", + checksum: "b816f366489d22ed70b84f105a19ce63810fee7295e3b3612fdf7e09c26fc9e9", + }, + { + filePath: "testdata/demo4.qwd", + checksum: "6b9088a13fc08609ca58e9887379e743beae0c0752939c001ac35d81a8f9c5af", + }, + { + filePath: "testdata/demo5.qwd", + checksum: "698b1961ee8ac009fff062255cece5ab6729c50df9f6ece2d1cf7f1c52406c13", + }, + { + filePath: "testdata/demo6.qwd", + checksum: "796357af178feb0c5fd5bff9cc6423914a36cc028f172b92c1336f1000e48d74", + }, +} + +func TestParse(t *testing.T) { + for _, qt := range qwdTests { + t.Run(qt.filePath, func(t *testing.T) { + data, err := ioutil.ReadFile(qt.filePath) + if err != nil { + t.Errorf("unable to open demo file, %v", err) + } + + demo, err := Parse(context.New(), data) + if err != nil { + t.Errorf("unable to parse demo, %v", err) + } + + h := sha256.New() + h.Write(demo.Bytes()) + checksum := fmt.Sprintf("%x", h.Sum(nil)) + if checksum != qt.checksum { + t.Errorf("sha256 checksums didn't match") + t.Logf("output: %#v", checksum) + t.Logf("expected: %#v", qt.checksum) + } + }) + } +} diff --git a/demo/qwd/read.go b/demo/qwd/read.go new file mode 100644 index 0000000..fdcee77 --- /dev/null +++ b/demo/qwd/read.go @@ -0,0 +1,42 @@ +package qwd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" + "github.com/osm/quake/packet" + "github.com/osm/quake/packet/svc" +) + +type Read struct { + Size uint32 + Packet packet.Packet +} + +func (cmd *Read) Bytes() []byte { + buf := buffer.New() + + buf.PutUint32(cmd.Size) + buf.PutBytes(cmd.Packet.Bytes()) + + return buf.Bytes() +} + +func parseRead(ctx *context.Context, buf *buffer.Buffer) (*Read, error) { + var err error + var cmd Read + + if cmd.Size, err = buf.GetUint32(); err != nil { + return nil, err + } + + bytes, err := buf.GetBytes(int(cmd.Size)) + if err != nil { + return nil, err + } + + if cmd.Packet, err = svc.Parse(ctx, bytes); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/qwd/set.go b/demo/qwd/set.go new file mode 100644 index 0000000..d7cc48d --- /dev/null +++ b/demo/qwd/set.go @@ -0,0 +1,35 @@ +package qwd + +import ( + "github.com/osm/quake/common/buffer" + "github.com/osm/quake/common/context" +) + +type Set struct { + SeqOut uint32 + SeqIn uint32 +} + +func (cmd *Set) Bytes() []byte { + buf := buffer.New() + + buf.PutUint32(cmd.SeqOut) + buf.PutUint32(cmd.SeqIn) + + return buf.Bytes() +} + +func parseSet(ctx *context.Context, buf *buffer.Buffer) (*Set, error) { + var err error + var cmd Set + + if cmd.SeqOut, err = buf.GetUint32(); err != nil { + return nil, err + } + + if cmd.SeqIn, err = buf.GetUint32(); err != nil { + return nil, err + } + + return &cmd, nil +} diff --git a/demo/qwd/testdata/demo1.qwd b/demo/qwd/testdata/demo1.qwd Binary files differnew file mode 100644 index 0000000..afc2c30 --- /dev/null +++ b/demo/qwd/testdata/demo1.qwd diff --git a/demo/qwd/testdata/demo2.qwd b/demo/qwd/testdata/demo2.qwd Binary files differnew file mode 100644 index 0000000..55f5306 --- /dev/null +++ b/demo/qwd/testdata/demo2.qwd diff --git a/demo/qwd/testdata/demo3.qwd b/demo/qwd/testdata/demo3.qwd Binary files differnew file mode 100644 index 0000000..e04d332 --- /dev/null +++ b/demo/qwd/testdata/demo3.qwd diff --git a/demo/qwd/testdata/demo4.qwd b/demo/qwd/testdata/demo4.qwd Binary files differnew file mode 100644 index 0000000..005a143 --- /dev/null +++ b/demo/qwd/testdata/demo4.qwd diff --git a/demo/qwd/testdata/demo5.qwd b/demo/qwd/testdata/demo5.qwd Binary files differnew file mode 100644 index 0000000..a78e779 --- /dev/null +++ b/demo/qwd/testdata/demo5.qwd diff --git a/demo/qwd/testdata/demo6.qwd b/demo/qwd/testdata/demo6.qwd Binary files differnew file mode 100644 index 0000000..78e6abc --- /dev/null +++ b/demo/qwd/testdata/demo6.qwd |
