175 lines
5.2 KiB
Go
175 lines
5.2 KiB
Go
|
|
package benchfbs
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
flatbuffers "github.com/google/flatbuffers/go"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// Vec3 mirrors the MoveMessage's Vector3 fields for FlatBuffers encoding.
|
|||
|
|
type Vec3 struct {
|
|||
|
|
X, Y, Z float32
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// MoveMsg is the Go struct used in the FlatBuffers benchmark.
|
|||
|
|
type MoveMsg struct {
|
|||
|
|
Position Vec3
|
|||
|
|
Velocity [3]float32
|
|||
|
|
Waypoints []Vec3
|
|||
|
|
PlayerID uint32
|
|||
|
|
Active, Visible, Ghost bool
|
|||
|
|
Name string
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// vtable slot indices for MoveMessage fields (0-based slot -> vtable offset = 4 + 2*slot)
|
|||
|
|
// slot 0 -> position (vtable offset 4)
|
|||
|
|
// slot 1 -> velocity (vtable offset 6)
|
|||
|
|
// slot 2 -> waypoints (vtable offset 8)
|
|||
|
|
// slot 3 -> player_id (vtable offset 10)
|
|||
|
|
// slot 4 -> active (vtable offset 12)
|
|||
|
|
// slot 5 -> visible (vtable offset 14)
|
|||
|
|
// slot 6 -> ghost (vtable offset 16)
|
|||
|
|
// slot 7 -> name (vtable offset 18)
|
|||
|
|
const (
|
|||
|
|
slotPosition = 0
|
|||
|
|
slotVelocity = 1
|
|||
|
|
slotWaypoints = 2
|
|||
|
|
slotPlayerID = 3
|
|||
|
|
slotActive = 4
|
|||
|
|
slotVisible = 5
|
|||
|
|
slotGhost = 6
|
|||
|
|
slotName = 7
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// buildVec3 writes a Vec3 as a table with 3 float32 fields and returns its offset.
|
|||
|
|
// Vec3 slots: x=0, y=1, z=2
|
|||
|
|
func buildVec3(b *flatbuffers.Builder, v Vec3) flatbuffers.UOffsetT {
|
|||
|
|
b.StartObject(3)
|
|||
|
|
b.PrependFloat32Slot(0, v.X, 0)
|
|||
|
|
b.PrependFloat32Slot(1, v.Y, 0)
|
|||
|
|
b.PrependFloat32Slot(2, v.Z, 0)
|
|||
|
|
return b.EndObject()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Marshal serialises msg into a FlatBuffer using b and returns the finished bytes.
|
|||
|
|
// The builder is reset before use, so callers can reuse it across calls.
|
|||
|
|
func Marshal(b *flatbuffers.Builder, msg *MoveMsg) []byte {
|
|||
|
|
b.Reset()
|
|||
|
|
|
|||
|
|
// 1. Build all variable-length data first (must be done outside object construction).
|
|||
|
|
|
|||
|
|
// name string
|
|||
|
|
nameOff := b.CreateString(msg.Name)
|
|||
|
|
|
|||
|
|
// velocity vector: 3 × float32
|
|||
|
|
b.StartVector(4, 3, 4)
|
|||
|
|
for i := 2; i >= 0; i-- {
|
|||
|
|
b.PrependFloat32(msg.Velocity[i])
|
|||
|
|
}
|
|||
|
|
velOff := b.EndVector(3)
|
|||
|
|
|
|||
|
|
// waypoints vector: repeated Vec3 tables (build each table first, collect offsets)
|
|||
|
|
wpOffsets := make([]flatbuffers.UOffsetT, len(msg.Waypoints))
|
|||
|
|
for i, wp := range msg.Waypoints {
|
|||
|
|
wpOffsets[i] = buildVec3(b, wp)
|
|||
|
|
}
|
|||
|
|
b.StartVector(4, len(wpOffsets), 4)
|
|||
|
|
for i := len(wpOffsets) - 1; i >= 0; i-- {
|
|||
|
|
b.PrependUOffsetT(wpOffsets[i])
|
|||
|
|
}
|
|||
|
|
wpVecOff := b.EndVector(len(wpOffsets))
|
|||
|
|
|
|||
|
|
// position table
|
|||
|
|
posOff := buildVec3(b, msg.Position)
|
|||
|
|
|
|||
|
|
// 2. Build the MoveMessage table.
|
|||
|
|
b.StartObject(8)
|
|||
|
|
b.PrependUOffsetTSlot(slotPosition, posOff, 0)
|
|||
|
|
b.PrependUOffsetTSlot(slotVelocity, velOff, 0)
|
|||
|
|
b.PrependUOffsetTSlot(slotWaypoints, wpVecOff, 0)
|
|||
|
|
b.PrependUint32Slot(slotPlayerID, msg.PlayerID, 0)
|
|||
|
|
b.PrependBoolSlot(slotActive, msg.Active, false)
|
|||
|
|
b.PrependBoolSlot(slotVisible, msg.Visible, false)
|
|||
|
|
b.PrependBoolSlot(slotGhost, msg.Ghost, false)
|
|||
|
|
b.PrependUOffsetTSlot(slotName, nameOff, 0)
|
|||
|
|
root := b.EndObject()
|
|||
|
|
|
|||
|
|
b.Finish(root)
|
|||
|
|
return b.FinishedBytes()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// readVec3 reads a Vec3 from a table at the given absolute position in buf.
|
|||
|
|
func readVec3(buf []byte, tablePos flatbuffers.UOffsetT) Vec3 {
|
|||
|
|
tab := flatbuffers.Table{Bytes: buf, Pos: tablePos}
|
|||
|
|
var v Vec3
|
|||
|
|
if o := tab.Offset(4); o != 0 { // slot 0 -> vtable offset 4
|
|||
|
|
v.X = tab.GetFloat32(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
if o := tab.Offset(6); o != 0 { // slot 1 -> vtable offset 6
|
|||
|
|
v.Y = tab.GetFloat32(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
if o := tab.Offset(8); o != 0 { // slot 2 -> vtable offset 8
|
|||
|
|
v.Z = tab.GetFloat32(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
return v
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Unmarshal reads all fields from a finished FlatBuffer into out.
|
|||
|
|
func Unmarshal(buf []byte, out *MoveMsg) {
|
|||
|
|
// The root offset is stored at byte 0 of the finished buffer.
|
|||
|
|
rootPos := flatbuffers.GetUOffsetT(buf)
|
|||
|
|
tab := flatbuffers.Table{Bytes: buf, Pos: rootPos}
|
|||
|
|
|
|||
|
|
// position (slot 0, vtable offset 4)
|
|||
|
|
if o := tab.Offset(4); o != 0 {
|
|||
|
|
absOff := tab.Pos + flatbuffers.UOffsetT(o)
|
|||
|
|
posPos := tab.Indirect(absOff)
|
|||
|
|
out.Position = readVec3(buf, posPos)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// velocity vector (slot 1, vtable offset 6)
|
|||
|
|
if o := tab.Offset(6); o != 0 {
|
|||
|
|
vecStart := tab.Vector(flatbuffers.UOffsetT(o))
|
|||
|
|
for i := 0; i < 3; i++ {
|
|||
|
|
out.Velocity[i] = flatbuffers.GetFloat32(buf[int(vecStart)+i*4:])
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// waypoints vector (slot 2, vtable offset 8)
|
|||
|
|
if o := tab.Offset(8); o != 0 {
|
|||
|
|
n := tab.VectorLen(flatbuffers.UOffsetT(o))
|
|||
|
|
out.Waypoints = make([]Vec3, n)
|
|||
|
|
vecStart := tab.Vector(flatbuffers.UOffsetT(o))
|
|||
|
|
for i := 0; i < n; i++ {
|
|||
|
|
// Each element is an UOffsetT pointing to the table.
|
|||
|
|
elemOff := vecStart + flatbuffers.UOffsetT(i*4)
|
|||
|
|
tablePos := elemOff + flatbuffers.GetUOffsetT(buf[elemOff:])
|
|||
|
|
out.Waypoints[i] = readVec3(buf, tablePos)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// player_id (slot 3, vtable offset 10)
|
|||
|
|
if o := tab.Offset(10); o != 0 {
|
|||
|
|
out.PlayerID = tab.GetUint32(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// active (slot 4, vtable offset 12)
|
|||
|
|
if o := tab.Offset(12); o != 0 {
|
|||
|
|
out.Active = tab.GetBool(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// visible (slot 5, vtable offset 14)
|
|||
|
|
if o := tab.Offset(14); o != 0 {
|
|||
|
|
out.Visible = tab.GetBool(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ghost (slot 6, vtable offset 16)
|
|||
|
|
if o := tab.Offset(16); o != 0 {
|
|||
|
|
out.Ghost = tab.GetBool(tab.Pos + flatbuffers.UOffsetT(o))
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// name (slot 7, vtable offset 18)
|
|||
|
|
if o := tab.Offset(18); o != 0 {
|
|||
|
|
absOff := tab.Pos + flatbuffers.UOffsetT(o)
|
|||
|
|
out.Name = tab.String(absOff)
|
|||
|
|
}
|
|||
|
|
}
|