delete everything

i didn't like it
types
Jordan Orelli 8 years ago
parent 16aa368ca1
commit f150e8aff1

@ -1,17 +0,0 @@
package ent
import (
"strconv"
)
type array struct {
slots []interface{}
_slotType string
decoder
}
func (a *array) slotName(slot int) string { return strconv.Itoa(slot) }
func (a *array) slotValue(slot int) interface{} { return a.slots[slot] }
func (a *array) slotType(slot int) string { return a._slotType }
func (a *array) slotDecoder(slot int) decoder { return a.decoder }
func (a *array) setSlotValue(slot int, val interface{}) { a.slots[slot] = val }

@ -1,54 +0,0 @@
package ent
import (
"fmt"
"github.com/jordanorelli/hyperstone/dota"
)
// Class represents a set of constraints around an Entity.
type Class struct {
name Symbol
Version int
Fields []*Field
// all other entities for this class use this instance as a prototype
baseline *Entity
// maps field names back to their indexes. Entities use this to access
// their own fields by name instead of by slot.
fieldNames map[string]int
}
func (c *Class) Name() string { return c.name.String() }
func (c *Class) Slotted() bool { return true }
func (c *Class) Id() classId { return classId{name: c.name, version: c.Version} }
func (c *Class) New(serial int, baseline bool) *Entity {
e := &Entity{
Class: c,
slots: make([]interface{}, len(c.Fields)),
serial: serial,
isBaseline: baseline,
}
for slot := range e.slots {
e.slots[slot] = c.Fields[slot].initializer()
}
return e
}
func (c Class) String() string {
return fmt.Sprintf("{%s %d}", c.Name, c.Version)
}
// A class is identified by the union of its name and version.
type classId struct {
name Symbol
version int
}
func (c *Class) fromProto(v *dota.ProtoFlattenedSerializerT, fields []Field) {
c.Fields = make([]*Field, len(v.GetFieldsIndex()))
for i, fi := range v.GetFieldsIndex() {
c.Fields[i] = &fields[fi]
}
}

@ -1,20 +0,0 @@
package ent
import (
"strconv"
)
type cutlVector struct {
slots []interface{}
_slotType string
decoder
}
func (v *cutlVector) slotName(slot int) string { return strconv.Itoa(slot) }
func (v *cutlVector) slotValue(slot int) interface{} { return v.slots[slot] }
func (v *cutlVector) slotType(slot int) string { return v._slotType }
func (v *cutlVector) slotDecoder(slot int) decoder { return v.decoder }
func (v *cutlVector) setSlotValue(slot int, val interface{}) {
v.slots[slot] = val
}

@ -1,232 +0,0 @@
package ent
import (
// "strings"
"github.com/jordanorelli/hyperstone/bit"
)
// a decoder decodes an entity value off of a bit reader
type decoder func(bit.Reader) interface{}
// creates a new field decoder for the field f.
func newFieldDecoder(n *Namespace, f *Field) decoder {
Debug.Printf("new decoder: type: %s name: %s sendNode: %s\n\tbits: %d low: %v high: %v\n\tflags: %d serializer: %v serializerVersion: %v\n\tclass: %v encoder: %v", f._type, f.name, f.sendNode, f.bits, f.low, f.high, f.flags, f.serializer, f.serializerVersion, f.class, f.encoder)
typeName := f._type.String()
switch typeName {
case "bool":
return decodeBool
case "uint8", "uint16", "uint32", "uint64":
return decodeVarInt64
case "Color":
return decodeColor
case "int8", "int16", "int32", "int64":
return decodeZigZag
case "CNetworkedQuantizedFloat", "float32":
return floatDecoder(f)
case "Vector":
return vectorDecoder(f)
case "QAngle":
return qangleDecoder(f)
case "CGameSceneNodeHandle":
// ehhh maybe no?
return decodeVarInt32
case "CUtlStringToken":
return symbolDecoder(n)
case "CUtlSymbolLarge", "char":
return decodeString
}
// the field is itself an entity contained within the outer entity.
if f.class != nil {
return entityDecoder(f.class)
}
// for compound types such as handles, vectors (in the c++ std::vector
// sense), and arrays
switch f.typeSpec.kind {
case t_element:
Debug.Printf("weird typespec: we shouldn't have elements here: %v", f.typeSpec)
return func(bit.Reader) interface{} {
Info.Fatalf("unable to decode element of type: %v", f.typeSpec.name)
return nil
}
case t_object:
return func(br bit.Reader) interface{} {
Debug.Printf("unable to decode object of type: %v", f.typeSpec.name)
return decodeVarInt32(br)
}
case t_array:
return arrayDecoder(n, f)
case t_template:
return templateDecoder(f)
case t_pointer:
return decodeBool
}
panic("fart")
}
func decodeBool(br bit.Reader) interface{} { return bit.ReadBool(br) }
func decodeVarInt32(br bit.Reader) interface{} { return bit.ReadVarInt32(br) }
func decodeVarInt64(br bit.Reader) interface{} { return bit.ReadVarInt(br) }
func decodeZigZag(br bit.Reader) interface{} { return bit.ReadZigZag(br) }
func decodeString(br bit.Reader) interface{} { return bit.ReadString(br) }
type color struct{ r, g, b, a uint8 }
func decodeColor(br bit.Reader) interface{} {
u := bit.ReadVarInt(br)
return color{
r: uint8(u & 0xff000000),
g: uint8(u & 0x00ff0000),
b: uint8(u & 0x0000ff00),
a: uint8(u & 0x000000ff),
}
}
func entityDecoder(c *Class) decoder {
return func(br bit.Reader) interface{} {
bit.ReadBool(br) // what does this do
return c.New(-1, false)
}
}
func vectorDecoder(f *Field) decoder {
if f.encoder != nil {
switch f.encoder.String() {
case "normal":
return decodeNormalVector
default:
return nil
}
}
fn := floatDecoder(f)
if fn == nil {
return nil
}
return func(br bit.Reader) interface{} {
return vector{fn(br).(float32), fn(br).(float32), fn(br).(float32)}
}
}
func decodeNormalVector(br bit.Reader) interface{} {
var v vector
x, y := bit.ReadBool(br), bit.ReadBool(br)
if x {
v.x = bit.ReadNormal(br)
}
if y {
v.y = bit.ReadNormal(br)
}
// here comes a shitty hack!
bit.ReadBool(br)
// discard this flag, it's concerned with the sign of the z value, which
// we're skipping.
return v
// ok, so. I have a suspicion that what we're interested in here is a
// surface normal, and that it's describing something about the geometry of
// the scene. I can't for the life of me see why in the hell we'd *ever*
// care about this in the context of parsing a replay, so I'm just turning
// off the z calculation. What follows is the original implementation as
// adapted from Manta and Clarity. The reason I care to skip this is that
// it involves a sqrt, which is a super slow operatation, and one worth
// dispensing with if you don't need the data that it produces.
//
// p := v.x*v.x + v.y*v.y
// if p < 1.0 {
// v.z = float32(math.Sqrt(float64(1.0 - p)))
// }
// if bit.ReadBool(br) {
// // we might wind up with the float representation of negative zero here,
// // but as far as I can tell, negative zero is fine because negative
// // zero is equivalent to positive zero. They'll print differently, but
// // I don't think we care about that.
// v.z = -v.z
// }
// return v
}
// decodes a qangle, which is a representation of an euler angle. that is, it's
// a three-angle encoding of orientation.
// https://developer.valvesoftware.com/wiki/QAngle
//
// the x, y, and z in this case do not refer to positions along a set of
// cartesian axes, but degress of rotation in an Euler angle.
//
// (-45,10,0) means 45° up, 10° left and 0° roll.
func qangleDecoder(f *Field) decoder {
if f.encoder != nil && f.encoder.String() == "qangle_pitch_yaw" {
return nil
}
bits := f.bits
if bits == 32 {
return nil
}
if bits == 0 {
return func(br bit.Reader) interface{} {
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
}
}
return func(br bit.Reader) interface{} {
return vector{
x: bit.ReadAngle(br, bits),
y: bit.ReadAngle(br, bits),
z: bit.ReadAngle(br, bits),
}
}
}
func arrayDecoder(n *Namespace, f *Field) decoder {
return func(br bit.Reader) interface{} {
Debug.Printf("dunno what this int32 val does in array decoder: %d", bit.ReadVarInt32(br))
if f.initializer != nil {
return f.initializer()
}
return nil
}
}
func templateDecoder(f *Field) decoder {
switch f.typeSpec.template {
case "CHandle":
return decodeVarInt32
case "CStrongHandle":
return decodeVarInt64
case "CUtlVector":
return func(br bit.Reader) interface{} {
v := decodeVarInt32(br)
Debug.Printf("dunno what this varint is for in the cutlvector decoder: %v", v)
return v
}
}
return nil
}
// so far a sanity check on the values I'm seeing out of this seem wrong.
func symbolDecoder(n *Namespace) decoder {
return func(br bit.Reader) interface{} {
u := bit.ReadVarInt32(br)
return n.Symbol(int(u))
}
}

@ -1,221 +0,0 @@
package ent
import (
"fmt"
"strconv"
"github.com/golang/protobuf/proto"
"github.com/jordanorelli/hyperstone/bit"
"github.com/jordanorelli/hyperstone/dota"
"github.com/jordanorelli/hyperstone/stbl"
)
// https://developer.valvesoftware.com/wiki/Entity_limit
//
// There can be up to 4096 entities. This total is split into two groups of 2048:
// Non-networked entities, which exist only on the client or server (e.g.
// death ragdolls on client, logicals on server).
// Entities with associated edicts, which can cross the client/server divide.
//
// If the game tries to assign a 2049th edict it will exit with an error
// message, but if it tries to create a 2049th non-networked entity it will
// merely refuse and print a warning to the console. The logic behind this
// may be that an entity spawned dynamically (i.e. not present in the map)
// but not assigned an edict probably isn't too important.
const e_limit = 2048
// Dict corresponds to the edict_t in Valve's documentation for the Source
// engine. See here: https://developer.valvesoftware.com/wiki/Edict_t
//
// From the Valve docs:
// edict_t ("entity dictionary") is an interface struct that allows entities
// to cross the client/server divide: with one attached, an entity has the
// same index at both ends. The edict also manages the state of the entity's
// DataTable and provides a common representation across all DLLs. It cannot
// be used on the client.
type Dict struct {
*Namespace
entities []*Entity
hidx map[int]*Entity // handle index
br *bit.BufReader
sr *selectionReader
// a reference to our string table of entity baseline data. For whatever
// reason, the first set of baselines sometimes come in before the classes
// are defined.
base *stbl.Table
}
func NewDict(sd *stbl.Dict) *Dict {
d := &Dict{
Namespace: new(Namespace),
entities: make([]*Entity, e_limit),
br: new(bit.BufReader),
sr: new(selectionReader),
base: sd.TableForName("instancebaseline"),
}
sd.WatchTable("instancebaseline", d.updateBaselines)
return d
}
// creates an entity with the provided id. the entity's contents data are read
// off of the Dict's internal bit stream br
func (d *Dict) createEntity(id int) error {
classId := int(d.readClassId(d.br))
if len(d.Namespace.classes) == 0 {
return fmt.Errorf("unable to create entity %d: namespace has no classes", id)
}
serial := int(d.br.ReadBits(17))
classV := int(bit.ReadVarInt(d.br))
className := d.classIds[classId]
class := d.Class(className, classV)
if class == nil {
return fmt.Errorf("unable to create entity %d: no class found for class name %s, version %d", className, classV)
}
e := class.New(serial, false)
d.entities[id] = e
Debug.Printf("create entity id: %d serial: %d classId: %d className: %v class: %v\n", id, serial, classId, className, class)
if err := fillSlots(e, class.Name(), d.sr, d.br); err != nil {
return fmt.Errorf("failed to create entity %d (%s): %v", id, className, err)
}
return nil
}
func (d *Dict) getEntity(id int) *Entity {
if id < 0 || id >= e_limit {
Debug.Printf("edict refused getEntity request for invalid id %d", id)
return nil
}
return d.entities[id]
}
func (d *Dict) updateEntity(id int) error {
Debug.Printf("update entity id: %d\n", id)
e := d.getEntity(id)
if e == nil {
return fmt.Errorf("update entity %d refused: no such entity", id)
}
if err := fillSlots(e, e.Class.String(), d.sr, d.br); err != nil {
return fmt.Errorf("failed to update entity %d (%s): %v", id, e.Class.Name(), err)
}
return nil
}
func (d *Dict) deleteEntity(id int) error {
Debug.Printf("delete entity id: %d\n", id)
if id < 0 || id >= e_limit {
// we're probably reading corrupt shit if we get here
return fmt.Errorf("delete entity %d refused: id is out of bounds", id)
}
if d.entities[id] == nil {
// this one's probably ok to let fly, but it's probably a sign that
// something is wrong elsewhere.
Debug.Printf("delete entity %d refused: no such entity", id)
return nil
}
d.entities[id] = nil
return nil
}
func (d *Dict) leaveEntity(id int) error {
Debug.Printf("leave entity id: %d\n", id)
// what the shit does this do?
return nil
}
func (d *Dict) Handle(m proto.Message) {
switch v := m.(type) {
case *dota.CDemoSendTables:
d.mergeSendTables(v)
d.syncBaselines()
case *dota.CDemoClassInfo:
d.mergeClassInfo(v)
d.syncBaselines()
case *dota.CSVCMsg_PacketEntities:
if err := d.mergeEntities(v); err != nil {
Info.Fatalf("merge entities error: %v", err)
}
}
}
func (d *Dict) mergeEntities(m *dota.CSVCMsg_PacketEntities) error {
data := m.GetEntityData()
Debug.Printf("packet header MaxEntries: %d UpdatedEntries: %v IsDelta: %t UpdateBaseline: %t Baseline: %d DeltaFrom: %d PendingFullFrame: %t ActiveSpawngroupHandle: %d", m.GetMaxEntries(), m.GetUpdatedEntries(), m.GetIsDelta(), m.GetUpdateBaseline(), m.GetBaseline(), m.GetDeltaFrom(), m.GetPendingFullFrame(), m.GetActiveSpawngroupHandle())
d.br.SetSource(data)
id := -1
for i := 0; i < int(m.GetUpdatedEntries()); i++ {
id++
// there may be a jump indicator, indicating how many id positions
// to skip.
id += int(bit.ReadUBitVar(d.br))
// next two bits encode one of four entity mutate operations
var fn func(int) error
switch d.br.ReadBits(2) {
case 0:
fn = d.updateEntity
case 1:
fn = d.leaveEntity
case 2:
fn = d.createEntity
case 3:
fn = d.deleteEntity
}
if err := fn(id); err != nil {
return fmt.Errorf("error on entity %d: %v", id, err)
}
}
return nil
}
func (d *Dict) updateBaselines(t *stbl.Table) {
d.base = t
d.syncBaselines()
}
func (d *Dict) syncBaselines() error {
if !d.hasClassinfo() {
Debug.Printf("syncBaselines skip: no classInfo yet")
return nil
}
Debug.Printf("syncBaselines start")
if d.base == nil {
return fmt.Errorf("syncBaselines failed: reference to baseline string table is nil")
}
for _, e := range d.base.Entries() {
id, err := strconv.Atoi(e.Key)
if err != nil {
Debug.Printf("syncBaselines skipping entry with key %s: key failed to parse to integer: %v", e.Key, err)
continue
}
c := d.ClassByNetId(id)
if c == nil {
Debug.Printf("syncBaselines skipping entry with key %s: no such class", e.Key)
continue
}
if c.baseline == nil {
c.baseline = c.New(-1, true)
}
if e.Value == nil || len(e.Value) == 0 {
Debug.Printf("syncBaselines skipping entry with key %s: value is empty", e.Key)
continue
}
d.br.SetSource(e.Value)
Debug.Printf("syncBaselines has new baseline for class %v", c)
if err := fillSlots(c.baseline, c.Name(), d.sr, d.br); err != nil {
return fmt.Errorf("syncBaselines failed to fill a baseline: %v", err)
}
}
return nil
}

@ -1,23 +0,0 @@
package ent
type Entity struct {
*Class
serial int
slots []interface{}
isBaseline bool
}
func (e *Entity) slotName(n int) string { return e.Class.Fields[n].name.String() }
func (e *Entity) slotType(n int) string { return e.Class.Fields[n]._type.String() }
func (e *Entity) slotValue(n int) interface{} {
v := e.slots[n]
if v != nil {
return v
}
if !e.isBaseline && e.Class.baseline != nil {
return e.Class.baseline.slotValue(n)
}
return nil
}
func (e *Entity) slotDecoder(n int) decoder { return e.Class.Fields[n].decoder }
func (e *Entity) setSlotValue(n int, v interface{}) { e.slots[n] = v }

@ -0,0 +1,19 @@
package ent
import (
"github.com/golang/protobuf/proto"
"github.com/jordanorelli/hyperstone/bit"
)
type Env struct {
source bit.BufReader
}
func (e *Env) Handle(m proto.Message) error {
return nil
}
func (e *Env) setSource(buf []byte) {
e.source.SetSource(buf)
}

@ -1,109 +0,0 @@
package ent
import (
"bytes"
"fmt"
"github.com/jordanorelli/hyperstone/dota"
)
/*
type Field struct {
Name string
Type
}
*/
type Field struct {
_type Symbol // type of data held by the field
typeSpec typeSpec
name Symbol // name of the field
sendNode Symbol // not sure what this is
bits uint // number of bits used to encode field?
low float32 // lower limit of field values
high float32 // upper limit of field values
flags int // used by float decoder
serializer *Symbol // the field is an entity with this class
serializerVersion *int32
class *Class // source class on which the field was originally defined
encoder *Symbol // binary encoder, named explicitly in protobuf
decoder // decodes field values from a bit stream
initializer func() interface{}
isTemplate bool // whether or not the field is a template type
templateType string
elemType string
}
func (f Field) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "{type: %s name: %s send: %s", f._type, f.name, f.sendNode)
if f.bits > 0 {
fmt.Fprintf(&buf, " bits: %d", f.bits)
}
if f.flags > 0 {
fmt.Fprintf(&buf, " flags: %d", f.flags)
}
fmt.Fprintf(&buf, " low: %f", f.low)
fmt.Fprintf(&buf, " high: %f", f.high)
if f.serializer != nil {
fmt.Fprintf(&buf, " serializer: %s", *f.serializer)
}
if f.serializerVersion != nil {
fmt.Fprintf(&buf, " serializer_v: %d", *f.serializerVersion)
}
if f.encoder != nil {
fmt.Fprintf(&buf, " encoder: %s", *f.encoder)
}
fmt.Fprint(&buf, "}")
return buf.String()
}
func (f *Field) fromProto(flat *dota.ProtoFlattenedSerializerFieldT, t *SymbolTable) {
f._type = t.Symbol(int(flat.GetVarTypeSym()))
f.name = t.Symbol(int(flat.GetVarNameSym()))
f.bits = uint(flat.GetBitCount())
f.flags = int(flat.GetEncodeFlags())
f.low = flat.GetLowValue()
f.high = flat.GetHighValue()
f.initializer = nilInitializer
if flat.FieldSerializerNameSym == nil {
f.serializer = nil
} else {
f.serializer = new(Symbol)
*f.serializer = t.Symbol(int(flat.GetFieldSerializerNameSym()))
}
f.serializerVersion = flat.FieldSerializerVersion
// panic if we don't have a send node cause that shit is corrupt yo
f.sendNode = t.Symbol(int(*flat.SendNodeSym))
Debug.Printf("new field: %v", f)
}
// creates a new field which is a sort of virtual field that represents what a
// field woudl look like if we had one for a container field's elements.
// honestly this is a really shitty hack it just seems easier than rewriting
// the newFieldDecoder logic.
func (f *Field) memberField() *Field {
mf := new(Field)
*mf = *f
mf.typeSpec = *f.typeSpec.member
// yeahhhh
mf._type = Symbol{0, &SymbolTable{mf.typeSpec.name}}
return mf
}
func (f *Field) isContainer() bool {
if f.typeSpec.kind == t_array {
return true
}
if f.typeSpec.kind == t_template {
if f.typeSpec.template == "CUtlVector" {
return true
}
}
return false
}
func nilInitializer() interface{} { return nil }

@ -1,93 +0,0 @@
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
}

@ -1,84 +0,0 @@
package ent
import (
"math"
"github.com/jordanorelli/hyperstone/bit"
)
func floatDecoder(f *Field) decoder {
if f.encoder != nil && f.encoder.String() == "coord" {
return nil
}
if f.bits <= 0 || f.bits >= 32 {
return ieeeFloat32Decoder
}
// a quantized field value must have some range specified, otherwise the
// quantization makes no sense.
if f.low == 0 && f.high == 0 {
panic("quantization rules make no sense")
}
bits := f.bits
low := f.low
high := f.high
flags := f.flags
// there's a flag that's -8 and i don't know what to do with it. I'm just
// gonna mask away everything except the three least significant bits and
// pray for the best.
flags = flags & 7
// number of input steps
steps := int(1<<f.bits - 1)
// keep the inverse to mult instead of divide later
inv_steps := 1.0 / float32(steps)
// total range of values
span := f.high - f.low
if span < 0 {
panic("quantization span is backwards")
}
// output width of each step
step_width := span * inv_steps
var special *float32
switch {
case flags&f_min > 0:
special = new(float32)
*special = low
case flags&f_max > 0:
special = new(float32)
*special = high
case flags&f_center > 0:
special = new(float32)
middle := (high + low) * 0.5
// if we're within a step of zero just return zero.
if middle > 0 && middle-step_width < 0 || middle < 0 && middle+step_width > 0 {
middle = 0
}
*special = middle
}
return func(br bit.Reader) interface{} {
if special != nil && bit.ReadBool(br) {
Debug.Printf("decode float type: %s low: %f high: %f bits: %d steps: %d span: %f flags: %d special: %v", f._type.String(), low, high, bits, steps, span, flags, *special)
return *special
}
u := br.ReadBits(bits)
out := low + float32(u)*inv_steps*span
Debug.Printf("decode float type: %s low: %f high: %f bits: %d bitVal: %d steps: %d span: %f flags: %d output: %v", f._type.String(), low, high, bits, u, steps, span, flags, out)
return out
}
}
// reads an IEEE 754 binary float value off of the stream
func ieeeFloat32Decoder(br bit.Reader) interface{} {
return math.Float32frombits(uint32(br.ReadBits(32)))
}

@ -1,24 +0,0 @@
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()
}

@ -1,6 +1,7 @@
package ent package ent
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -10,3 +11,7 @@ var (
Debug = log.New(ioutil.Discard, "DEBUG ent: ", 0) Debug = log.New(ioutil.Discard, "DEBUG ent: ", 0)
Info = log.New(os.Stdout, "INFO end: ", 0) Info = log.New(os.Stdout, "INFO end: ", 0)
) )
func wrap(err error, t string, args ...interface{}) error {
return fmt.Errorf(t+": %v", append(args, err)...)
}

@ -1,246 +0,0 @@
package ent
import (
"fmt"
"math"
"github.com/golang/protobuf/proto"
"github.com/jordanorelli/hyperstone/bit"
"github.com/jordanorelli/hyperstone/dota"
)
// Namespace registers the names of known classess, associating their ids to
// their network types.
type Namespace struct {
SymbolTable
idBits int
// maps ClassInfo ids to class names
classIds map[int]string
// maps classes to their {name, version} id pairs
classes map[classId]*Class
// maps a class name to every version of the class
classesByName map[string]map[int]*Class
}
// Merges in the ClassInfo data found in the replay protobufs
func (n *Namespace) mergeClassInfo(ci *dota.CDemoClassInfo) {
if n.classIds == nil {
n.classIds = make(map[int]string, len(ci.GetClasses()))
}
for _, class := range ci.GetClasses() {
n.classIds[int(class.GetClassId())] = class.GetNetworkName()
}
n.idBits = int(math.Floor(math.Log2(float64(len(n.classIds))))) + 1
}
func (n *Namespace) hasClassinfo() bool {
return n.classIds != nil && len(n.classIds) > 0
}
// merges the send table data found in the replay protobufs. The send table
// data contains a specification for an entity type system.
func (n *Namespace) mergeSendTables(st *dota.CDemoSendTables) error {
// sendtables only has one field, a binary data field.
Debug.Printf("merge send tables")
data := st.GetData()
br := bit.NewBytesReader(data)
// body is length-prefixed
size := int(bit.ReadVarInt(br))
buf := make([]byte, size)
br.Read(buf)
flat := dota.CSVCMsg_FlattenedSerializer{}
if err := proto.Unmarshal(buf, &flat); err != nil {
return fmt.Errorf("unable to merge send tables: %v", err)
}
n.SymbolTable = SymbolTable(flat.GetSymbols())
// the full set of fields that may appear on the classes is read first.
// each class will have a list of fields.
fields := make([]Field, len(flat.GetFields()))
for i, f := range flat.GetFields() {
fields[i].fromProto(f, &n.SymbolTable)
}
n.classes = make(map[classId]*Class, len(flat.GetSerializers()))
n.classesByName = make(map[string]map[int]*Class, len(flat.GetSerializers()))
// each serializer in the source data generates a class.
for _, c := range flat.GetSerializers() {
name := n.Symbol(int(c.GetSerializerNameSym()))
version := int(c.GetSerializerVersion())
Debug.Printf("new class: %s %v", name, version)
class := Class{name: name, Version: version}
class.fromProto(c, fields)
id := classId{name: name, version: version}
n.classes[id] = &class
if n.classesByName[name.String()] == nil {
n.classesByName[name.String()] = map[int]*Class{version: &class}
} else {
n.classesByName[name.String()][version] = &class
}
}
for i := range fields {
f := &fields[i]
if f.serializer != nil {
if f.serializerVersion != nil {
f.class = n.classesByName[f.serializer.String()][int(*f.serializerVersion)]
} else {
f.class = n.NewestClass(f.serializer.String())
}
}
// for some fields, we want to initialize a zero value on the baseline
// instance. specifically, we do this for arrays so that we can't try
// to index into nil.
f.typeSpec = parseTypeName(n, f._type.String())
if f.isContainer() {
mf := f.memberField()
fn := newFieldDecoder(n, mf)
if f.typeSpec.kind == t_array {
f.initializer = func() interface{} {
return &array{
slots: make([]interface{}, f.typeSpec.size),
_slotType: mf._type.String(),
decoder: fn,
}
}
} else if f.typeSpec.kind == t_template && f.typeSpec.template == "CUtlVector" {
f.initializer = func() interface{} {
return &cutlVector{
slots: make([]interface{}, f.typeSpec.size),
_slotType: mf._type.String(),
decoder: fn,
}
}
}
}
// we also wait until after we've discovered all of the classes to
// build the field decoder functions, because some fields are
// themselves entities.
f.decoder = newFieldDecoder(n, f)
}
for _, ff := range flat.GetFields() {
t, err := parseType(n, ff)
if err != nil {
Debug.Printf(" parseType error: %v", err)
} else {
Debug.Printf(" parseType type: %v", t)
}
}
return br.Err()
}
/*
func (n *Namespace) newMergeSendTables(st *dota.CDemoSendTables) error {
// sendtables only has one field, a binary data field. It's not immediately
// clear why this message exists at all when it could simply contain
// CSVMsg_FlattenedSerializer.
data := st.GetData()
br := bit.NewBytesReader(data)
// body is length-prefixed
size := int(bit.ReadVarInt(br))
buf := make([]byte, size)
br.Read(buf)
flat := dota.CSVCMsg_FlattenedSerializer{}
if err := proto.Unmarshal(buf, &flat); err != nil {
return fmt.Errorf("unable to merge send tables: %v", err)
}
return n.mergeSerializers(&flat)
}
func (n *Namespace) mergeSerializers(flat *dota.CSVCMsg_FlattenedSerializer) error {
// most of the names and associated strings are interned in a symbol table.
// We'll need these first since they're referenced throughought the class
// and field definitions.
n.SymbolTable = SymbolTable(flat.GetSymbols())
n.classes = make(map[classId]*Class, len(flat.GetSerializers()))
n.classesByName = make(map[string]map[int]*Class, len(flat.GetSerializers()))
// some fields refer to classes, but classes are collections of fields.
// Their references are potentially cyclical. We start by creating empty
// classes so that fields may point to them.
for _, s := range flat.GetSerializers() {
name_sym := n.Symbol(int(s.GetSerializerNameSym()))
ver := int(s.GetSerializerVersion())
class := Class{name: name_sym, Version: ver}
n.classes[class.Id()] = &class
if n.classesByName[class.Name()] == nil {
n.classesByName[class.Name()] = make(map[int]*Class)
}
n.classesByName[class.Name()][ver] = &class
}
// type ProtoFlattenedSerializerFieldT struct {
// VarTypeSym *int32
// VarNameSym *int32
// VarEncoderSym *int32
// FieldSerializerNameSym *int32
// FieldSerializerVersion *int32
// BitCount *int32
// LowValue *float32
// HighValue *float32
// EncodeFlags *int32
// SendNodeSym *int32
// }
// next we parse all of the fields along with their type definitions
fields := make(map[int]Field, len(flat.GetFields()))
for id, flatField := range flat.GetFields() {
t := parseType(n, flatField)
fields[id].Name = n.Symbol(int(flatField.GetVarNameSym())).String()
}
os.Exit(1)
return nil
}
*/
func (n *Namespace) readClassId(r bit.Reader) int {
return int(r.ReadBits(uint(n.idBits)))
}
func (n *Namespace) Class(name string, version int) *Class {
return n.classesByName[name][version]
}
// retrieves the newest version of a class, as referenced by name.
func (n *Namespace) NewestClass(name string) *Class {
versions, newest := n.classesByName[name], -1
for v, _ := range versions {
if v > newest {
newest = v
}
}
if newest == -1 {
Info.Fatalf("class %s has no known versions in its version map", name)
}
return versions[newest]
}
func (n *Namespace) ClassByNetId(id int) *Class {
name, ok := n.classIds[id]
if !ok {
Info.Fatalf("can't find class name for net id %d", id)
}
return n.NewestClass(name)
}
func (n *Namespace) HasClass(name string) bool {
_, ok := n.classesByName[name]
return ok
}

@ -1,106 +0,0 @@
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},
{name: "HSequence", read: readIntMinusOne},
}
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()
}
// ------------------------------------------------------------------------------
// uints
// ------------------------------------------------------------------------------
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()
}
// ------------------------------------------------------------------------------
// ints
// ------------------------------------------------------------------------------
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()
}
// what in the good fuck is this
func readIntMinusOne(br bit.Reader, d *Dict) (interface{}, error) {
return bit.ReadVarInt(br) - 1, br.Err()
}

@ -1,74 +0,0 @@
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()
}

@ -19,39 +19,6 @@ type selection struct {
func (s selection) String() string { return fmt.Sprint(s.path()) } func (s selection) String() string { return fmt.Sprint(s.path()) }
func (s selection) path() []int { return s.vals[:s.count] } func (s selection) path() []int { return s.vals[:s.count] }
func (s selection) fill(offset int, displayPath string, dest slotted, br bit.Reader) error {
slot := s.vals[offset]
if s.count-offset <= 0 {
panic("selection makes no sense")
}
switch s.count - offset {
case 1:
fn := dest.slotDecoder(slot)
if fn == nil {
switch dest.(type) {
case *Entity:
Debug.Printf("%s %s (%s)", s, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot))
return nil
default:
Info.Printf("slotted value %v has no decoder for slot %d", dest, slot)
return nil
}
}
old := dest.slotValue(slot)
val := fn(br)
dest.setSlotValue(slot, val)
Debug.Printf("%s %s (%s): %v -> %v", s, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot), old, val)
return nil
default:
v := dest.slotValue(slot)
vs, ok := v.(slotted)
if !ok {
return fmt.Errorf("selection %s at offset %d (%d) refers to a slot (%s) that contains a non-slotted type (%s) with value %v", s, offset, slot, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), dest.slotType(slot), v)
}
return s.fill(offset+1, fmt.Sprintf("%s.%s", displayPath, dest.slotName(slot)), vs, br)
}
}
// selectionReader reads a set of field selections off of the wire. the // selectionReader reads a set of field selections off of the wire. the
// selections are represented as arrays of slot positions to be traversed in // selections are represented as arrays of slot positions to be traversed in
// order to select an entity slot. // order to select an entity slot.

@ -1,28 +0,0 @@
package ent
import (
"fmt"
"github.com/jordanorelli/hyperstone/bit"
)
type slotted interface {
slotName(int) string
slotValue(int) interface{}
slotType(int) string
slotDecoder(int) decoder
setSlotValue(int, interface{})
}
func fillSlots(dest slotted, displayPath string, sr *selectionReader, br bit.Reader) error {
selections, err := sr.readSelections(br, htree)
if err != nil {
return fmt.Errorf("error filling slots: %v", err)
}
for _, s := range selections {
if err := s.fill(0, displayPath, dest, br); err != nil {
return fmt.Errorf("error filling slots: %v", err)
}
}
return nil
}

@ -1,17 +0,0 @@
package ent
// the internal representation of table data refers to all labels as
// interned strings (symbols). This array of string contains the mapping of
// symbol ids to symbol display representations. The sample replay I have
// at the time of writing this contains 2215 symbols in its symbol table.
// The dota replay format uses an ordered list of symbols.
type SymbolTable []string
func (t *SymbolTable) Symbol(id int) Symbol { return Symbol{id: id, table: t} }
type Symbol struct {
id int
table *SymbolTable
}
func (s Symbol) String() string { return (*s.table)[s.id] }

@ -1,99 +0,0 @@
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()
}

@ -1,120 +0,0 @@
package ent
import (
"fmt"
"strconv"
"strings"
)
const (
t_element = iota // a known element class
t_object // c++ object type that is not a known element class
t_array // c++ array type
t_template // c++ template type
t_pointer // c++ pointer
)
// constant identifiers
var cIdents = map[string]int{"MAX_ABILITY_DRAFT_ABILITIES": 48}
type typeSpec struct {
name string
kind int
size int
template string
member *typeSpec
}
func (t typeSpec) String() string {
if t.member != nil {
return fmt.Sprintf("{%v %v %v %v %v}", t.name, t.kind, t.size, t.template, *t.member)
}
return fmt.Sprintf("{%v %v %v %v %v}", t.name, t.kind, t.size, t.template, t.member)
}
func parseTypeName(n *Namespace, s string) typeSpec {
s = strings.TrimSpace(s)
t := typeSpec{name: s}
if n.HasClass(s) {
t.kind = t_element
return t
}
if strings.HasSuffix(s, "*") {
t.kind = t_pointer
t.member = new(typeSpec)
*t.member = parseTypeName(n, s[:len(s)-2])
return t
}
// presumably this is some sort of array type
if strings.ContainsRune(s, '[') {
memName, count := parseArrayName(s)
t.kind = t_array
t.size = count
t.member = new(typeSpec)
*t.member = parseTypeName(n, memName)
return t
}
if strings.ContainsRune(s, '<') {
t.kind = t_template
template, member := parseTemplateName(s)
t.template = template
t.member = new(typeSpec)
*t.member = parseTypeName(n, member)
return t
}
t.kind = t_object
return t
}
func parseArrayName(s string) (string, int) {
runes := []rune(s)
if runes[len(runes)-1] != ']' {
panic("invalid array type name: " + s)
}
for i := len(runes) - 2; i >= 0; i-- {
if runes[i] == '[' {
ns := strings.TrimSpace(string(runes[i+1 : len(runes)-1]))
n, err := strconv.Atoi(ns)
if err != nil {
n = cIdents[ns]
if n <= 0 {
panic("invalid array type name: " + err.Error())
}
}
return strings.TrimSpace(string(runes[:i])), n
}
}
panic("invalid array type name: " + s)
}
func parseTemplateName(s string) (string, string) {
if strings.ContainsRune(s, ',') {
panic("can't handle templates with multiple parameters")
}
runes := []rune(s)
template := ""
depth := 0
bracket_start := -1
for i, r := range runes {
if r == '<' {
if depth == 0 {
bracket_start = i
template = strings.TrimSpace(string(runes[:i]))
}
depth++
}
if r == '>' {
depth--
if depth == 0 {
return template, strings.TrimSpace(string(runes[bracket_start+1 : i]))
}
}
}
panic("invalid template type definition: " + s)
}

@ -1,7 +0,0 @@
package ent
type vector struct {
x float32
y float32
z float32
}

@ -1,18 +0,0 @@
package main
import (
"fmt"
)
type entity struct {
t entityType
size uint32
body []byte
}
func (e entity) String() string {
if len(e.body) < 30 {
return fmt.Sprintf("{entity type: %s size: %d data: %x}", e.t, e.size, e.body)
}
return fmt.Sprintf("{entity type: %s size: %d data: %x...}", e.t, e.size, e.body[:27])
}

@ -143,10 +143,10 @@ func main() {
case "entities": case "entities":
ent.Debug = log.New(os.Stdout, "", 0) ent.Debug = log.New(os.Stdout, "", 0)
sd := stbl.NewDict() sd := stbl.NewDict()
ed := ent.NewDict(sd) env := new(ent.Env)
handle = func(m proto.Message) { handle = func(m proto.Message) {
sd.Handle(m) sd.Handle(m)
ed.Handle(m) env.Handle(m)
} }
default: default:
bail(1, "no such action: %s", flag.Arg(0)) bail(1, "no such action: %s", flag.Arg(0))

Loading…
Cancel
Save