in the middle of redoing the whole decode thing
parent
59949e2e80
commit
8d06c4ecc3
@ -0,0 +1,93 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/jordanorelli/hyperstone/bit"
|
||||
"github.com/jordanorelli/hyperstone/dota"
|
||||
)
|
||||
|
||||
const (
|
||||
f_min = 1 << iota
|
||||
f_max
|
||||
f_center
|
||||
)
|
||||
|
||||
func parseFloatType(n *Namespace, flat *dota.ProtoFlattenedSerializerFieldT) (Type, error) {
|
||||
if flat.VarEncoderSym != nil {
|
||||
encoder := n.Symbol(int(flat.GetVarEncoderSym())).String()
|
||||
switch encoder {
|
||||
case "coord":
|
||||
return nil, fmt.Errorf("coord encoder isn't dont yet")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown float encoder: %s", encoder)
|
||||
}
|
||||
}
|
||||
|
||||
if flat.BitCount != nil {
|
||||
bits := int(flat.GetBitCount())
|
||||
switch {
|
||||
case bits < 0:
|
||||
return nil, fmt.Errorf("invalid bit count on float field: %d", bits)
|
||||
case bits < 32:
|
||||
return quantizedFloat(n, flat)
|
||||
case bits == 0, bits == 32:
|
||||
// these seem meaningless, which is suspicious.
|
||||
default:
|
||||
return nil, fmt.Errorf("bit count is too high on float field: %d", bits)
|
||||
}
|
||||
}
|
||||
|
||||
if flat.LowValue != nil || flat.HighValue != nil {
|
||||
return nil, fmt.Errorf("float32 with a low or high value isn't supported")
|
||||
}
|
||||
|
||||
type_name := n.Symbol(int(flat.GetVarTypeSym())).String()
|
||||
return &Primitive{name: type_name, read: readFloat32}, nil
|
||||
}
|
||||
|
||||
func quantizedFloat(n *Namespace, flat *dota.ProtoFlattenedSerializerFieldT) (Type, error) {
|
||||
if flat.LowValue == nil && flat.HighValue == nil {
|
||||
return nil, fmt.Errorf("quantizedFloat has no boundaries")
|
||||
}
|
||||
|
||||
bits := uint(flat.GetBitCount())
|
||||
low, high := flat.GetLowValue(), flat.GetHighValue()
|
||||
flags := int(flat.GetEncodeFlags())
|
||||
|
||||
flags = flags & 7 // dunno how to handle -8 lol
|
||||
steps := uint(1<<bits - 1) // total number of intervals
|
||||
span := high - low // total range of values
|
||||
step_width := span / float32(steps) // output width of each step
|
||||
if span < 0 {
|
||||
return nil, fmt.Errorf("invalid quantization span")
|
||||
}
|
||||
|
||||
var special *float32
|
||||
switch {
|
||||
case flags&f_min > 0:
|
||||
special = &low
|
||||
case flags&f_max > 0:
|
||||
special = &high
|
||||
case flags&f_center > 0:
|
||||
middle := (high + low) * 0.5
|
||||
special = &middle
|
||||
}
|
||||
|
||||
read := func(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
if special != nil && bit.ReadBool(br) {
|
||||
return *special, nil
|
||||
}
|
||||
u := br.ReadBits(bits)
|
||||
return low + float32(u)*step_width, br.Err()
|
||||
}
|
||||
|
||||
type_name := n.Symbol(int(flat.GetVarTypeSym())).String()
|
||||
return &Primitive{name: type_name, read: read}, nil
|
||||
}
|
||||
|
||||
// reads an IEEE 754 binary float value off of the stream
|
||||
func readFloat32(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return math.Float32frombits(uint32(br.ReadBits(32))), nil
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/jordanorelli/hyperstone/bit"
|
||||
)
|
||||
|
||||
type Handle struct{ name string }
|
||||
|
||||
func (h *Handle) Name() string { return h.name }
|
||||
func (h *Handle) New(...interface{}) interface{} { return nil }
|
||||
func (h *Handle) Slotted() bool { return false }
|
||||
|
||||
func (h *Handle) Read(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
id := int(bit.ReadVarInt(br))
|
||||
e, ok := d.hidx[id]
|
||||
if !ok {
|
||||
if br.Err() != nil {
|
||||
return nil, br.Err()
|
||||
}
|
||||
return nil, fmt.Errorf("no entity found with handle %d", id)
|
||||
}
|
||||
return e, br.Err()
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"github.com/jordanorelli/hyperstone/bit"
|
||||
)
|
||||
|
||||
var primitives map[string]Primitive
|
||||
|
||||
// a Primitive type in the ent object system.
|
||||
type Primitive struct {
|
||||
name string
|
||||
read decodeFn
|
||||
alloc func() interface{}
|
||||
}
|
||||
|
||||
func (p *Primitive) New(args ...interface{}) interface{} {
|
||||
if p.alloc != nil {
|
||||
return p.alloc()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (p *Primitive) Name() string { return p.name }
|
||||
func (p *Primitive) Slotted() bool { return false }
|
||||
|
||||
func (p *Primitive) Read(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return p.read(br, d)
|
||||
}
|
||||
|
||||
func init() {
|
||||
types := []Primitive{
|
||||
{name: "bool", read: readBool},
|
||||
{name: "uint8", read: readUint8},
|
||||
{name: "uint16", read: readUint16},
|
||||
{name: "uint32", read: readUint32},
|
||||
{name: "uint64", read: readUint64},
|
||||
{name: "int8", read: readInt8},
|
||||
{name: "int16", read: readInt16},
|
||||
{name: "int32", read: readInt32},
|
||||
{name: "int64", read: readInt64},
|
||||
{name: "Color", read: readColor},
|
||||
}
|
||||
primitives = make(map[string]Primitive, len(types))
|
||||
for _, t := range types {
|
||||
primitives[t.name] = t
|
||||
}
|
||||
}
|
||||
|
||||
func readBool(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return bit.ReadBool(br), br.Err()
|
||||
}
|
||||
|
||||
func readUint8(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return uint8(br.ReadBits(8)), br.Err()
|
||||
}
|
||||
|
||||
func readUint16(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return uint16(bit.ReadVarInt(br)), br.Err()
|
||||
}
|
||||
|
||||
func readUint32(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return uint32(bit.ReadVarInt(br)), br.Err()
|
||||
}
|
||||
|
||||
func readUint64(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return bit.ReadVarInt(br), br.Err()
|
||||
}
|
||||
|
||||
func readInt8(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return int8(bit.ReadZigZag(br)), br.Err()
|
||||
}
|
||||
|
||||
func readInt16(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return int16(bit.ReadZigZag(br)), br.Err()
|
||||
}
|
||||
|
||||
func readInt32(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return int32(bit.ReadZigZag(br)), br.Err()
|
||||
}
|
||||
|
||||
func readInt64(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return bit.ReadZigZag(br), br.Err()
|
||||
}
|
||||
|
||||
func readColor(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
u := bit.ReadVarInt(br)
|
||||
return color{
|
||||
r: uint8(u & 0xff000000),
|
||||
g: uint8(u & 0x00ff0000),
|
||||
b: uint8(u & 0x0000ff00),
|
||||
a: uint8(u & 0x000000ff),
|
||||
}, br.Err()
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/jordanorelli/hyperstone/bit"
|
||||
"github.com/jordanorelli/hyperstone/dota"
|
||||
)
|
||||
|
||||
func parseQAngleType(n *Namespace, flat *dota.ProtoFlattenedSerializerFieldT) (Type, error) {
|
||||
type_name := n.Symbol(int(flat.GetVarTypeSym())).String()
|
||||
if flat.VarEncoderSym != nil {
|
||||
encoder := n.Symbol(int(flat.GetVarEncoderSym())).String()
|
||||
switch encoder {
|
||||
case "qangle_pitch_yaw":
|
||||
return nil, fmt.Errorf("that qangle pitch yaw thing isn't done yet")
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown qangle encoder: %s", encoder)
|
||||
}
|
||||
}
|
||||
if flat.BitCount == nil {
|
||||
return nil, fmt.Errorf("dunno what to do when qangle type has no bitcount")
|
||||
}
|
||||
if flat.GetBitCount() < 0 {
|
||||
return nil, fmt.Errorf("negative bit count wtf")
|
||||
}
|
||||
bits := uint(flat.GetBitCount())
|
||||
switch bits {
|
||||
case 0:
|
||||
return &Primitive{name: type_name, read: readQAngleCoords}, nil
|
||||
case 32:
|
||||
return &Primitive{name: type_name, read: readQAngleFloats}, nil
|
||||
default:
|
||||
return &Primitive{name: type_name, read: qangleReader(bits)}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func qangleReader(bits uint) decodeFn {
|
||||
return func(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return &vector{
|
||||
x: bit.ReadAngle(br, bits),
|
||||
y: bit.ReadAngle(br, bits),
|
||||
z: bit.ReadAngle(br, bits),
|
||||
}, br.Err()
|
||||
}
|
||||
}
|
||||
|
||||
func readQAngleCoords(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
var (
|
||||
v vector
|
||||
x = bit.ReadBool(br)
|
||||
y = bit.ReadBool(br)
|
||||
z = bit.ReadBool(br)
|
||||
)
|
||||
if x {
|
||||
v.x = bit.ReadCoord(br)
|
||||
}
|
||||
if y {
|
||||
v.y = bit.ReadCoord(br)
|
||||
}
|
||||
if z {
|
||||
v.z = bit.ReadCoord(br)
|
||||
}
|
||||
return v, br.Err()
|
||||
}
|
||||
|
||||
func readQAngleFloats(br bit.Reader, d *Dict) (interface{}, error) {
|
||||
return &vector{
|
||||
x: math.Float32frombits(uint32(br.ReadBits(32))),
|
||||
y: math.Float32frombits(uint32(br.ReadBits(32))),
|
||||
z: math.Float32frombits(uint32(br.ReadBits(32))),
|
||||
}, br.Err()
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
package ent
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/jordanorelli/hyperstone/bit"
|
||||
"github.com/jordanorelli/hyperstone/dota"
|
||||
)
|
||||
|
||||
type decodeFn func(bit.Reader, *Dict) (interface{}, error)
|
||||
|
||||
// a Type in the entity type system. Note that not every type is necessarily an
|
||||
// entity type, since there are necessarily primitives, and above that, arrays
|
||||
// and generics.
|
||||
type Type interface {
|
||||
// creates a new value of the given type.
|
||||
New(...interface{}) interface{}
|
||||
|
||||
// name is primarily of interest for debugging
|
||||
Name() string
|
||||
|
||||
// whether or not the produced values are expected to be slotted.
|
||||
Slotted() bool
|
||||
|
||||
// reads a value of this type off of the bit reader
|
||||
Read(bit.Reader, *Dict) (interface{}, error)
|
||||
}
|
||||
|
||||
func parseType(n *Namespace, flat *dota.ProtoFlattenedSerializerFieldT) (Type, error) {
|
||||
Debug.Printf("parseType: %s", prettyFlatField(n, flat))
|
||||
type_name := n.Symbol(int(flat.GetVarTypeSym())).String()
|
||||
|
||||
if prim, ok := primitives[type_name]; ok {
|
||||
Debug.Printf(" parseType: found primitive with name %s", type_name)
|
||||
return &prim, nil
|
||||
}
|
||||
|
||||
if n.HasClass(type_name) {
|
||||
Debug.Printf(" parseType: found class with name %s", type_name)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
switch type_name {
|
||||
case "float32", "CNetworkedQuantizedFloat":
|
||||
Debug.Printf(" parseType: parsing as float type")
|
||||
return parseFloatType(n, flat)
|
||||
case "CGameSceneNodeHandle":
|
||||
return &Handle{name: "CGameSceneNodeHandle"}, nil
|
||||
case "QAngle":
|
||||
return parseQAngleType(n, flat)
|
||||
}
|
||||
|
||||
Debug.Printf(" parseType: failed")
|
||||
// type ProtoFlattenedSerializerFieldT struct {
|
||||
// VarTypeSym *int32
|
||||
// VarNameSym *int32
|
||||
// VarEncoderSym *int32
|
||||
// FieldSerializerNameSym *int32
|
||||
// FieldSerializerVersion *int32
|
||||
// BitCount *int32
|
||||
// LowValue *float32
|
||||
// HighValue *float32
|
||||
// EncodeFlags *int32
|
||||
// SendNodeSym *int32
|
||||
// }
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func prettyFlatField(n *Namespace, ff *dota.ProtoFlattenedSerializerFieldT) string {
|
||||
var buf bytes.Buffer
|
||||
fmt.Fprintf(&buf, "{type: %s", n.Symbol(int(ff.GetVarTypeSym())))
|
||||
fmt.Fprintf(&buf, " name: %s", n.Symbol(int(ff.GetVarNameSym())))
|
||||
if ff.BitCount != nil {
|
||||
fmt.Fprintf(&buf, " bits: %d", ff.GetBitCount())
|
||||
}
|
||||
if ff.LowValue != nil {
|
||||
fmt.Fprintf(&buf, " low: %f", ff.GetLowValue())
|
||||
}
|
||||
if ff.HighValue != nil {
|
||||
fmt.Fprintf(&buf, " high: %f", ff.GetHighValue())
|
||||
}
|
||||
if ff.EncodeFlags != nil {
|
||||
fmt.Fprintf(&buf, " flags: %d", ff.GetEncodeFlags())
|
||||
}
|
||||
if ff.FieldSerializerNameSym != nil {
|
||||
fmt.Fprintf(&buf, " serializer: %s", n.Symbol(int(ff.GetFieldSerializerNameSym())))
|
||||
}
|
||||
if ff.FieldSerializerVersion != nil {
|
||||
fmt.Fprintf(&buf, " version: %d", ff.GetFieldSerializerVersion())
|
||||
}
|
||||
if ff.SendNodeSym != nil {
|
||||
fmt.Fprintf(&buf, " send: %s", n.Symbol(int(ff.GetSendNodeSym())))
|
||||
}
|
||||
if ff.VarEncoderSym != nil {
|
||||
fmt.Fprintf(&buf, " encoder: %s", n.Symbol(int(ff.GetVarEncoderSym())))
|
||||
}
|
||||
fmt.Fprintf(&buf, "}")
|
||||
return buf.String()
|
||||
}
|
Loading…
Reference in New Issue