diff --git a/ent/class.go b/ent/class.go index aacec5f..6cb04c2 100644 --- a/ent/class.go +++ b/ent/class.go @@ -11,6 +11,10 @@ type Class struct { Fields []*Field } +func (c *Class) New() *Entity { + return &Entity{Class: c} +} + type classId struct { name Symbol version int diff --git a/ent/context.go b/ent/context.go index da1f7e1..f2d13ad 100644 --- a/ent/context.go +++ b/ent/context.go @@ -14,13 +14,21 @@ func NewContext() *Context { } func (c *Context) CreateEntity(id int, r bit.Reader) { + classId := int(c.readClassId(r)) + r.ReadBits(17) // ??? + classV := int(bit.ReadVarInt(r)) + className := c.classIds[classId] + class := c.Class(className, classV) + e := class.New() + e.Read(r) } -func (c *Context) GetEntity(id int) Entity { - return Entity{} +func (c *Context) UpdateEntity(id int, r bit.Reader) { + } func (c *Context) DeleteEntity(id int) { + } func (c *Context) LeaveEntity(id int) { diff --git a/ent/entity.go b/ent/entity.go index d782eb5..ff41d7c 100644 --- a/ent/entity.go +++ b/ent/entity.go @@ -1,8 +1,12 @@ package ent +import ( + "github.com/jordanorelli/hyperstone/bit" +) + type Entity struct { + *Class } -func (e *Entity) Update(raw []byte) { - +func (e *Entity) Read(br bit.Reader) { } diff --git a/ent/huff.go b/ent/huff.go new file mode 100644 index 0000000..a181648 --- /dev/null +++ b/ent/huff.go @@ -0,0 +1,182 @@ +package ent + +import ( + "fmt" + "io" + "sort" + + "github.com/jordanorelli/hyperstone/bit" +) + +type node interface { + weight() int + maxRank() int +} + +// intermediate node +type iNode struct{ left, right node } + +func (n iNode) String() string { + return fmt.Sprintf("{%d %d *}", n.left.weight()+n.right.weight(), n.maxRank()) +} + +func (n iNode) weight() int { return n.left.weight() + n.right.weight() } +func (n iNode) maxRank() int { + r := 0 + switch v := n.left.(type) { + case iNode: + r2 := v.maxRank() + if r2 > r { + r = r2 + } + case lNode: + if v.rank > r { + r = v.rank + } + } + switch v := n.right.(type) { + case iNode: + r2 := v.maxRank() + if r2 > r { + r = r2 + } + case lNode: + if v.rank > r { + r = v.rank + } + } + return r +} + +// leaf node +type lNode struct { + name string + rank int + freq int + fn func() +} + +func (n lNode) String() string { + return fmt.Sprintf("{%d %d %s}", n.freq, n.rank, n.name) +} + +func (n lNode) weight() int { return n.freq } +func (n lNode) maxRank() int { return n.rank } + +// three-way comparison for nodes, used in sorting +func n_compare(n1, n2 node) int { + switch { + case n1.weight() < n2.weight(): + return -1 + case n1.weight() > n2.weight(): + return 1 + case n1.maxRank() < n2.maxRank(): + return -1 + case n1.maxRank() > n2.maxRank(): + return 1 + default: + return 0 + } +} + +// joins two nodes, creating and returning their parent node +func n_join(n1, n2 node) node { + switch n_compare(n1, n2) { + case -1: + return iNode{n1, n2} + case 0, 1: + return iNode{n2, n1} + default: + panic("not reached") + } +} + +// a list of huffman nodes, for assembling a huffman tree +type nodeList []node + +func (l nodeList) Len() int { return len(l) } +func (l nodeList) Less(i, j int) bool { return n_compare(l[i], l[j]) == -1 } +func (l nodeList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } + +func makeTree(l nodeList) node { + // at each step: + // sort the list of nodes in the tree. + // remove the last two nodes, joining them to create their parent node. + // append this parent node to the list of nodes. + // repeat until only one node remains, which is the root node. + for len(l) > 1 { + sort.Sort(sort.Reverse(l)) + l = append(l[:len(l)-2], n_join(l[len(l)-2], l[len(l)-1])) + } + return l[0] +} + +func walk(n node, br bit.Reader) func() { + switch v := n.(type) { + case lNode: + return v.fn + case iNode: + if bit.ReadBool(br) { + return walk(v.right, br) + } else { + return walk(v.left, br) + } + default: + panic("not reached") + } +} + +func dump(n node, prefix string, w io.Writer) { + switch v := n.(type) { + case lNode: + fmt.Fprintf(w, "%s\t%v\n", prefix, v) + case iNode: + dump(v.left, prefix+"0", w) + dump(v.right, prefix+"1", w) + } +} + +var hlist = nodeList{ + lNode{"PlusOne", 0, 36271, func() {}}, + lNode{"FieldPathEncodeFinish", 39, 25474, func() {}}, + lNode{"PushOneLeftDeltaNRightNonZeroPack6Bits", 11, 10530, func() {}}, + lNode{"PlusTwo", 1, 10334, func() {}}, + lNode{"PlusN", 4, 4128, func() {}}, + lNode{"PushOneLeftDeltaOneRightNonZero", 8, 2942, func() {}}, + lNode{"PopAllButOnePlusOne", 29, 1837, func() {}}, + lNode{"PlusThree", 2, 1375, func() {}}, + lNode{"PlusFour", 3, 646, func() {}}, + lNode{"PopAllButOnePlusNPack6Bits", 32, 634, func() {}}, + lNode{"PushOneLeftDeltaNRightZero", 9, 560, func() {}}, + lNode{"PushOneLeftDeltaOneRightZero", 7, 521, func() {}}, + lNode{"PushOneLeftDeltaNRightNonZero", 10, 471, func() {}}, + lNode{"PopAllButOnePlusNPack3Bits", 31, 300, func() {}}, + lNode{"NonTopoPenultimatePlusOne", 37, 271, func() {}}, + lNode{"PushOneLeftDeltaNRightNonZeroPack8Bits", 12, 251, func() {}}, + lNode{"PopAllButOnePlusN", 30, 149, func() {}}, + lNode{"NonTopoComplexPack4Bits", 38, 99, func() {}}, + lNode{"NonTopoComplex", 36, 76, func() {}}, + lNode{"PushOneLeftDeltaZeroRightZero", 5, 35, func() {}}, + lNode{"PushOneLeftDeltaZeroRightNonZero", 6, 3, func() {}}, + lNode{"PopNAndNonTopographical", 35, 1, func() {}}, + lNode{"PopNPlusN", 34, 0, func() {}}, + lNode{"PopNPlusOne", 33, 0, func() {}}, + lNode{"PopOnePlusN", 28, 0, func() {}}, + lNode{"PopOnePlusOne", 27, 2, func() {}}, + lNode{"PushNAndNonTopological", 26, 310, func() {}}, + lNode{"PushN", 25, 0, func() {}}, + lNode{"PushThreePack5LeftDeltaN", 24, 0, func() {}}, + lNode{"PushThreeLeftDeltaN", 23, 0, func() {}}, + lNode{"PushTwoPack5LeftDeltaN", 22, 0, func() {}}, + lNode{"PushTwoLeftDeltaN", 21, 0, func() {}}, + lNode{"PushThreePack5LeftDeltaOne", 20, 0, func() {}}, + lNode{"PushThreeLeftDeltaOne", 19, 0, func() {}}, + lNode{"PushTwoPack5LeftDeltaOne", 18, 0, func() {}}, + lNode{"PushTwoLeftDeltaOne", 17, 0, func() {}}, + lNode{"PushThreePack5LeftDeltaZero", 16, 0, func() {}}, + lNode{"PushThreeLeftDeltaZero", 15, 0, func() {}}, + lNode{"PushTwoPack5LeftDeltaZero", 14, 0, func() {}}, + lNode{"PushTwoLeftDeltaZero", 13, 0, func() {}}, +} + +var htree = makeTree(hlist) diff --git a/ent/huff_test.go b/ent/huff_test.go new file mode 100644 index 0000000..13a7556 --- /dev/null +++ b/ent/huff_test.go @@ -0,0 +1,14 @@ +package ent + +import ( + "bytes" + "testing" +) + +func TestDump(t *testing.T) { + t.Log(hlist) + + var buf bytes.Buffer + dump(htree, "", &buf) + t.Logf("%s", buf.String()) +} diff --git a/ent/namespace.go b/ent/namespace.go index 12bf252..2c78bbc 100644 --- a/ent/namespace.go +++ b/ent/namespace.go @@ -81,6 +81,10 @@ func (n *Namespace) MergeSendTables(st *dota.CDemoSendTables) { } } -func (n *Namespace) ReadClassId(r bit.Reader) int { +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] +} diff --git a/entities.go b/entities.go index 93a7b61..782b7a0 100644 --- a/entities.go +++ b/entities.go @@ -49,13 +49,13 @@ func dumpEntities(m proto.Message) { // next two bits encode one of four entity mutate operations switch br.ReadBits(2) { case 0: - // update + ctx.UpdateEntity(id, br) case 1: - // leave + ctx.LeaveEntity(id) case 2: ctx.CreateEntity(id, br) case 3: - // delete + ctx.DeleteEntity(id) } } }