diff --git a/ent/atoms.go b/ent/atoms.go index 6e4be52..26b9576 100644 --- a/ent/atoms.go +++ b/ent/atoms.go @@ -2,15 +2,19 @@ package ent import ( "github.com/jordanorelli/hyperstone/bit" + "github.com/jordanorelli/hyperstone/dota" ) -var atom_types = map[string]tÿpe{ - "uint16": {"uint16", func(...interface{}) value { return new(uint16_v) }}, +var atom_types = map[string]typeFn{ + "uint16": func(r bit.Reader) (value, error) { + return uint16(bit.ReadVarInt(r)), r.Err() + }, } -type uint16_v uint16 - -func (u *uint16_v) read(r bit.Reader) error { - *u = uint16_v(bit.ReadVarInt(r)) - return r.Err() +func atomType(flat *dota.ProtoFlattenedSerializerFieldT, env *Env) tÿpe { + var_type := env.symbol(int(flat.GetVarTypeSym())) + if t, ok := atom_types[var_type]; ok { + return t + } + return nil } diff --git a/ent/field.go b/ent/field.go index cc18357..97d8657 100644 --- a/ent/field.go +++ b/ent/field.go @@ -11,14 +11,13 @@ type field struct { } func (f *field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, env *Env) error { - var_name := env.symbol(int(flat.GetVarNameSym())) - var_type := env.symbol(int(flat.GetVarTypeSym())) - - if t, ok := atom_types[var_type]; ok { - f.name = var_name - f.tÿpe = t - return nil + Debug.Printf("parse flat field: %s", prettyFlatField(flat, env)) + t := parseType(flat, env) + if t == nil { + return fmt.Errorf("unable to parse type: %s", prettyFlatField(flat, env)) } - return fmt.Errorf("unable to parse type: %s", prettyFlatField(flat, env)) + f.tÿpe = t + f.name = env.symbol(int(flat.GetVarNameSym())) + return nil } diff --git a/ent/float.go b/ent/float.go new file mode 100644 index 0000000..c7fd834 --- /dev/null +++ b/ent/float.go @@ -0,0 +1,67 @@ +package ent + +import ( + "fmt" + + "github.com/jordanorelli/hyperstone/bit" + "github.com/jordanorelli/hyperstone/dota" +) + +const ( + f_min = 1 << iota + f_max + f_center +) + +func qFloatType(flat *dota.ProtoFlattenedSerializerFieldT, env *Env) tÿpe { + if env.symbol(int(flat.GetVarTypeSym())) != "CNetworkedQuantizedFloat" { + return nil + } + if flat.GetBitCount() < 0 { + return typeError("quantized float has invalid negative bit count specifier") + } + if flat.GetHighValue()-flat.GetLowValue() < 0 { + return typeError("quantized float has invalid negative range") + } + t := qfloat_t{ + bits: uint(flat.GetBitCount()), + low: flat.GetLowValue(), + high: flat.GetHighValue(), + flags: int(flat.GetEncodeFlags()) & 0x7, + } + t.span = t.high - t.low + t.intervals = uint(1< 0 { + t.special = new(float32) + } + + switch { + case t.flags&f_min > 0: + *t.special = t.low + case t.flags&f_max > 0: + *t.special = t.high + case t.flags&f_center > 0: + *t.special = t.low + (t.high+t.low)*0.5 + } + return t +} + +type qfloat_t struct { + bits uint + low float32 + high float32 + flags int + span float32 // total range of values + intervals uint // number of intervals in the quantization range + interval float32 // width of one interval + special *float32 +} + +func (t qfloat_t) read(r bit.Reader) (value, error) { + if t.special != nil && bit.ReadBool(r) { + return *t.special, nil + } + return nil, fmt.Errorf("I'll get there") +} diff --git a/ent/type.go b/ent/type.go index 6213c78..6806b2c 100644 --- a/ent/type.go +++ b/ent/type.go @@ -1,6 +1,40 @@ package ent -type tÿpe struct { - name string - alloc func(...interface{}) value +import ( + "fmt" + + "github.com/jordanorelli/hyperstone/bit" + "github.com/jordanorelli/hyperstone/dota" +) + +type tÿpe interface { + read(bit.Reader) (value, error) +} + +type typeFn func(bit.Reader) (value, error) + +func (fn typeFn) read(r bit.Reader) (value, error) { return fn(r) } + +type typeParseFn func(*dota.ProtoFlattenedSerializerFieldT, *Env) tÿpe + +func parseType(flat *dota.ProtoFlattenedSerializerFieldT, env *Env) tÿpe { + coalesce := func(fns ...typeParseFn) tÿpe { + for _, fn := range fns { + if t := fn(flat, env); t != nil { + return t + } + } + return nil + } + return coalesce(atomType, qFloatType) +} + +// a type error is both an error and a type. It represents a type that we were +// unable to correctly parse. It can be interpreted as an error or as a type; +// when interpreted as a type, it errors every time it tries to read a value. +type typeError string + +func (e typeError) Error() string { return string(e) } +func (e typeError) read(r bit.Reader) (value, error) { + return nil, fmt.Errorf("type error: %s", string(e)) } diff --git a/ent/value.go b/ent/value.go index 453442b..2b252df 100644 --- a/ent/value.go +++ b/ent/value.go @@ -1,9 +1,3 @@ package ent -import ( - "github.com/jordanorelli/hyperstone/bit" -) - -type value interface { - read(bit.Reader) error -} +type value interface{}