From 31375289b0b67fce47b0c49b7b7d84b77ceddbe1 Mon Sep 17 00:00:00 2001 From: Tnze Date: Sat, 27 Jul 2024 23:53:35 +0800 Subject: [PATCH] Add tags implement --- bot/basic/basic.go | 1 + bot/basic/tags.go | 37 ++++++++++++++++++++++ bot/configuration.go | 73 +++++++++++++++++++++++++++++++++++++++++--- registry/README.md | 33 ++++++++++++++++++++ registry/codec.go | 11 +++++-- registry/network.go | 51 +++++++++++++++++++++++++++++-- registry/registry.go | 25 ++++++++++++--- 7 files changed, 218 insertions(+), 13 deletions(-) create mode 100644 bot/basic/tags.go create mode 100644 registry/README.md diff --git a/bot/basic/basic.go b/bot/basic/basic.go index 2e97ee0..6055f0c 100644 --- a/bot/basic/basic.go +++ b/bot/basic/basic.go @@ -43,6 +43,7 @@ func NewPlayer(c *bot.Client, settings Settings, events EventsListener) *Player bot.PacketHandler{Priority: 0, ID: packetid.ClientboundPing, F: p.handlePingPacket}, bot.PacketHandler{Priority: 0, ID: packetid.ClientboundCookieRequest, F: p.handleCookieRequestPacket}, bot.PacketHandler{Priority: 0, ID: packetid.ClientboundStoreCookie, F: p.handleStoreCookiePacket}, + bot.PacketHandler{Priority: 0, ID: packetid.ClientboundUpdateTags, F: p.handleUpdateTags}, ) events.attach(p) return p diff --git a/bot/basic/tags.go b/bot/basic/tags.go new file mode 100644 index 0000000..571a0aa --- /dev/null +++ b/bot/basic/tags.go @@ -0,0 +1,37 @@ +package basic + +import ( + "bytes" + "errors" + + pk "github.com/Tnze/go-mc/net/packet" +) + +func (p *Player) handleUpdateTags(packet pk.Packet) error { + r := bytes.NewReader(packet.Data) + + var length pk.VarInt + _, err := length.ReadFrom(r) + if err != nil { + return Error{err} + } + + var registryID pk.Identifier + for i := 0; i < int(length); i++ { + _, err = registryID.ReadFrom(r) + if err != nil { + return Error{err} + } + + registry := p.c.Registries.Registry(string(registryID)) + if registry == nil { + return Error{errors.New("unknown registry: " + string(registryID))} + } + + _, err = registry.ReadTagsFrom(r) + if err != nil { + return Error{err} + } + } + return nil +} diff --git a/bot/configuration.go b/bot/configuration.go index 99d328d..c43e875 100644 --- a/bot/configuration.go +++ b/bot/configuration.go @@ -153,9 +153,8 @@ func (c *Client) joinConfiguration(conn *net.Conn) error { if registry == nil { return ConfigErr{ErrStage, errors.New("unknown registry: " + string(registryID))} } - fmt.Println(registry) - _, err = registry.(pk.FieldDecoder).ReadFrom(r) + _, err = registry.ReadFrom(r) if err != nil { return ConfigErr{ErrStage, fmt.Errorf("failed to read registry %s: %w", registryID, err)} } @@ -207,7 +206,7 @@ func (c *Client) joinConfiguration(conn *net.Conn) error { var port pk.VarInt err := p.Scan(&host, &port) if err != nil { - return ConfigErr{"store cookie", err} + return ConfigErr{"transfer", err} } // TODO: trnasfer to the specific server // How does it work? Just connect the new server, and re-start at handshake? @@ -221,7 +220,39 @@ func (c *Client) joinConfiguration(conn *net.Conn) error { c.ConfigHandler.EnableFeature(features) case packetid.ClientboundConfigUpdateTags: - // TODO: Handle Tags + const ErrStage = "update tags" + r := bytes.NewReader(p.Data) + + var length pk.VarInt + _, err := length.ReadFrom(r) + if err != nil { + return ConfigErr{ErrStage, err} + } + + var registryID pk.Identifier + for i := 0; i < int(length); i++ { + _, err = registryID.ReadFrom(r) + if err != nil { + return ConfigErr{ErrStage, err} + } + + registry := c.Registries.Registry(string(registryID)) + if registry == nil { + // TODO: Sice our registry system is incompelted, ignore all tags bind to non-exist registry + _, err = idleTagsDecoder{}.ReadFrom(r) + if err != nil { + return ConfigErr{ErrStage, err} + } + continue + // return ConfigErr{ErrStage, errors.New("unknown registry: " + string(registryID))} + } + + _, err = registry.ReadTagsFrom(r) + if err != nil { + return ConfigErr{ErrStage, err} + } + } + case packetid.ClientboundConfigSelectKnownPacks: const ErrStage = "select known packs" packs := []DataPack{} @@ -329,3 +360,37 @@ func (d *DefaultConfigHandler) PopAllResourcePack() { func (d *DefaultConfigHandler) SelectDataPacks(packs []DataPack) []DataPack { return []DataPack{} } + +type idleTagsDecoder struct{} + +func (idleTagsDecoder) ReadFrom(r io.Reader) (int64, error) { + var count pk.VarInt + var tag pk.Identifier + var length pk.VarInt + n, err := count.ReadFrom(r) + if err != nil { + return n, err + } + for i := 0; i < int(count); i++ { + var n1, n2, n3 int64 + n1, err = tag.ReadFrom(r) + if err != nil { + return n + n1, err + } + n2, err = length.ReadFrom(r) + if err != nil { + return n + n1 + n2, err + } + n += n1 + n2 + + var id pk.VarInt + for i := 0; i < int(length); i++ { + n3, err = id.ReadFrom(r) + if err != nil { + return n + n3, err + } + n += n3 + } + } + return n, nil +} diff --git a/registry/README.md b/registry/README.md new file mode 100644 index 0000000..81429fc --- /dev/null +++ b/registry/README.md @@ -0,0 +1,33 @@ +# Registry System + +instance { + ResourceLocation { + namespace: string + path: string + } + + ResourceKey { + registryName: ResourceLocation + location: ResourceLocation + } + + registry { + getId(T): int + byId(int): T + + getKey(T): ResourceLocation + getResourceKey(T): ResourceKey + get(ResourceKey): T + get(ResourceLocation): T + + getTags(TagKey): (TagKey, *T[])[] + getTagNames(): TagKey[] + resetTags() + bindTags((TagKey, *T[])[]) + }[] + + TagKey { + *Registry + ResourceLocation + } +} diff --git a/registry/codec.go b/registry/codec.go index 01ce618..6aefbb8 100644 --- a/registry/codec.go +++ b/registry/codec.go @@ -1,10 +1,12 @@ package registry import ( + "io" "reflect" "github.com/Tnze/go-mc/chat" "github.com/Tnze/go-mc/nbt" + pk "github.com/Tnze/go-mc/net/packet" ) type NetworkCodec struct { @@ -72,7 +74,12 @@ type Dimension struct { MonsterSpawnBlockLightLimit int32 `nbt:"monster_spawn_block_light_limit"` } -func (c *NetworkCodec) Registry(id string) any { +type RegistryCodec interface { + pk.FieldDecoder + ReadTagsFrom(r io.Reader) (int64, error) +} + +func (c *NetworkCodec) Registry(id string) RegistryCodec { codecVal := reflect.ValueOf(c).Elem() codecTyp := codecVal.Type() numField := codecVal.NumField() @@ -82,7 +89,7 @@ func (c *NetworkCodec) Registry(id string) any { continue } if registryID == id { - return codecVal.Field(i).Addr().Interface() + return codecVal.Field(i).Addr().Interface().(RegistryCodec) } } return nil diff --git a/registry/network.go b/registry/network.go index 4bca5f9..aa89908 100644 --- a/registry/network.go +++ b/registry/network.go @@ -1,14 +1,15 @@ package registry import ( + "errors" "io" + "strconv" pk "github.com/Tnze/go-mc/net/packet" ) func (reg *Registry[E]) ReadFrom(r io.Reader) (int64, error) { var length pk.VarInt - n, err := length.ReadFrom(r) if err != nil { return n, err @@ -33,7 +34,7 @@ func (reg *Registry[E]) ReadFrom(r io.Reader) (int64, error) { } if hasData { - n3, err = pk.NBTField{V:&data, AllowUnknownFields: true}.ReadFrom(r) + n3, err = pk.NBTField{V: &data, AllowUnknownFields: true}.ReadFrom(r) if err != nil { return n + n1 + n2 + n3, err } @@ -44,3 +45,49 @@ func (reg *Registry[E]) ReadFrom(r io.Reader) (int64, error) { } return n, nil } + +func (reg *Registry[E]) ReadTagsFrom(r io.Reader) (int64, error) { + var count pk.VarInt + n, err := count.ReadFrom(r) + if err != nil { + return n, err + } + + var tag pk.Identifier + var length pk.VarInt + for i := 0; i < int(count); i++ { + var n1, n2, n3 int64 + + n1, err = tag.ReadFrom(r) + if err != nil { + return n + n1, err + } + + n2, err = length.ReadFrom(r) + if err != nil { + return n + n1 + n2, err + } + + n += n1 + n2 + values := make([]*E, length) + + var id pk.VarInt + for i := 0; i < int(length); i++ { + n3, err = id.ReadFrom(r) + if err != nil { + return n + n3, err + } + + if id < 0 || int(id) >= len(reg.values) { + err = errors.New("invalid id: " + strconv.Itoa(int(id))) + return n + n3, err + } + + values[i] = ®.values[id] + n += n3 + } + + reg.tags[string(tag)] = values + } + return n, nil +} diff --git a/registry/registry.go b/registry/registry.go index d93bd6e..46defce 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -4,6 +4,7 @@ type Registry[E any] struct { keys map[string]int32 values []E indices map[*E]int32 + tags map[string][]*E } func NewRegistry[E any]() Registry[E] { @@ -11,9 +12,17 @@ func NewRegistry[E any]() Registry[E] { keys: make(map[string]int32), values: make([]E, 0, 256), indices: make(map[*E]int32), + tags: make(map[string][]*E), } } +func (r *Registry[E]) Clear() { + r.keys = make(map[string]int32) + r.values = r.values[:0] + r.indices = make(map[*E]int32) + r.tags = make(map[string][]*E) +} + func (r *Registry[E]) Get(key string) (int32, *E) { id, ok := r.keys[key] if !ok { @@ -38,8 +47,14 @@ func (r *Registry[E]) Put(name string, data E) (id int32, val *E) { return } -func (r *Registry[E]) Clear() { - r.keys = make(map[string]int32) - r.values = r.values[:0] - r.indices = make(map[*E]int32) -} +// func (r *Registry[E]) BindTags(tag string, ids []int32) error { +// values := make([]*E, len(ids)) +// for i, id := range ids { +// if id < 0 || id >= int32(len(r.values)) { +// return errors.New("invalid id: " + strconv.Itoa(int(id))) +// } +// values[i] = &r.values[id] +// } +// r.tags[tag] = values +// return nil +// }