diff --git a/bot/client.go b/bot/client.go index 9b0c3cc..ae29081 100644 --- a/bot/client.go +++ b/bot/client.go @@ -53,6 +53,7 @@ func (c *Client) Close() error { func NewClient() *Client { return &Client{ Auth: Auth{Name: "Steve"}, + Registries: registry.NewNetworkCodec(), Events: Events{handlers: make([][]PacketHandler, packetid.ClientboundPacketIDGuard)}, LoginPlugin: make(map[string]CustomPayloadHandler), ConfigHandler: NewDefaultConfigHandler(), diff --git a/bot/configuration.go b/bot/configuration.go index 6102709..99d328d 100644 --- a/bot/configuration.go +++ b/bot/configuration.go @@ -3,11 +3,11 @@ package bot import ( "bytes" "errors" + "fmt" "io" "github.com/Tnze/go-mc/chat" "github.com/Tnze/go-mc/data/packetid" - "github.com/Tnze/go-mc/nbt" "github.com/Tnze/go-mc/net" pk "github.com/Tnze/go-mc/net/packet" ) @@ -141,12 +141,7 @@ func (c *Client) joinConfiguration(conn *net.Conn) error { case packetid.ClientboundConfigRegistryData: const ErrStage = "registry" - // err := p.Scan(pk.NBT(&c.ConfigData.Registries)) - // if err != nil { - // return ConfigErr{"registry data", err} - // } var registryID pk.Identifier - var length pk.VarInt r := bytes.NewReader(p.Data) _, err := registryID.ReadFrom(r) @@ -154,40 +149,15 @@ func (c *Client) joinConfiguration(conn *net.Conn) error { return ConfigErr{ErrStage, err} } - _, err = length.ReadFrom(r) - if err != nil { - return ConfigErr{ErrStage, err} - } - registry := c.Registries.Registry(string(registryID)) if registry == nil { return ConfigErr{ErrStage, errors.New("unknown registry: " + string(registryID))} } + fmt.Println(registry) - for i := 0; i < int(length); i++ { - var entryId pk.Identifier - var hasData pk.Boolean - var data nbt.RawMessage - _, err = entryId.ReadFrom(r) - if err != nil { - return ConfigErr{ErrStage, err} - } - - _, err = hasData.ReadFrom(r) - if err != nil { - return ConfigErr{ErrStage, err} - } - - if hasData { - _, err = pk.NBT(&data).ReadFrom(r) - if err != nil { - return ConfigErr{ErrStage, err} - } - err = registry.InsertWithNBT(string(entryId), data) - if err != nil { - return ConfigErr{ErrStage, err} - } - } + _, err = registry.(pk.FieldDecoder).ReadFrom(r) + if err != nil { + return ConfigErr{ErrStage, fmt.Errorf("failed to read registry %s: %w", registryID, err)} } case packetid.ClientboundConfigResourcePackPop: diff --git a/bot/msg/chat.go b/bot/msg/chat.go index e14cfa6..460cf5a 100644 --- a/bot/msg/chat.go +++ b/bot/msg/chat.go @@ -88,7 +88,7 @@ func (m *Manager) handlePlayerChat(packet pk.Packet) error { if !ok { return InvalidChatPacket{ErrUnknownPlayer} } - ct := m.c.Registries.ChatType.FindByID(chatType.ID) + ct := m.c.Registries.ChatType.GetByID(chatType.ID) if ct == nil { return InvalidChatPacket{ErrUnknwonChatType} } @@ -141,7 +141,7 @@ func (m *Manager) handleDisguisedChat(packet pk.Packet) error { return err } - ct := m.c.Registries.ChatType.FindByID(chatType.ID) + ct := m.c.Registries.ChatType.GetByID(chatType.ID) if ct == nil { return InvalidChatPacket{ErrUnknwonChatType} } diff --git a/bot/world/chunks.go b/bot/world/chunks.go index 8618936..7e5a7d0 100644 --- a/bot/world/chunks.go +++ b/bot/world/chunks.go @@ -41,7 +41,7 @@ func (w *World) onPlayerSpawn(pk.Packet) error { func (w *World) handleLevelChunkWithLightPacket(packet pk.Packet) error { var pos level.ChunkPos - currentDimType := w.c.Registries.DimensionType.FindByID(w.p.DimensionType) + currentDimType := w.c.Registries.DimensionType.GetByID(w.p.DimensionType) if currentDimType == nil { return fmt.Errorf("dimension type %d not found", w.p.DimensionType) } diff --git a/registry/codec.go b/registry/codec.go index 9491561..01ce618 100644 --- a/registry/codec.go +++ b/registry/codec.go @@ -21,6 +21,22 @@ type NetworkCodec struct { JukeboxSong Registry[nbt.RawMessage] `registry:"minecraft:jukebox_song"` } +func NewNetworkCodec() NetworkCodec { + return NetworkCodec{ + ChatType: NewRegistry[ChatType](), + DamageType: NewRegistry[DamageType](), + DimensionType: NewRegistry[Dimension](), + TrimMaterial: NewRegistry[nbt.RawMessage](), + TrimPattern: NewRegistry[nbt.RawMessage](), + WorldGenBiome: NewRegistry[nbt.RawMessage](), + Wolfvariant: NewRegistry[nbt.RawMessage](), + PaintingVariant: NewRegistry[nbt.RawMessage](), + BannerPattern: NewRegistry[nbt.RawMessage](), + Enchantment: NewRegistry[nbt.RawMessage](), + JukeboxSong: NewRegistry[nbt.RawMessage](), + } +} + type ChatType struct { Chat chat.Decoration `nbt:"chat"` Narration chat.Decoration `nbt:"narration"` @@ -56,7 +72,7 @@ type Dimension struct { MonsterSpawnBlockLightLimit int32 `nbt:"monster_spawn_block_light_limit"` } -func (c *NetworkCodec) Registry(id string) RegistryHandler { +func (c *NetworkCodec) Registry(id string) any { codecVal := reflect.ValueOf(c).Elem() codecTyp := codecVal.Type() numField := codecVal.NumField() @@ -66,12 +82,8 @@ func (c *NetworkCodec) Registry(id string) RegistryHandler { continue } if registryID == id { - return codecVal.Field(i).Addr().Interface().(RegistryHandler) + return codecVal.Field(i).Addr().Interface() } } return nil } - -type RegistryHandler interface { - InsertWithNBT(name string, data nbt.RawMessage) error -} diff --git a/registry/network.go b/registry/network.go new file mode 100644 index 0000000..4bca5f9 --- /dev/null +++ b/registry/network.go @@ -0,0 +1,46 @@ +package registry + +import ( + "io" + + 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 + } + + reg.Clear() + + var key pk.Identifier + var hasData pk.Boolean + for i := 0; i < int(length); i++ { + var data E + var n1, n2, n3 int64 + + n1, err = key.ReadFrom(r) + if err != nil { + return n + n1, err + } + + n2, err = hasData.ReadFrom(r) + if err != nil { + return n + n1 + n2, err + } + + if hasData { + n3, err = pk.NBTField{V:&data, AllowUnknownFields: true}.ReadFrom(r) + if err != nil { + return n + n1 + n2 + n3, err + } + reg.Put(string(key), data) + } + + n += n1 + n2 + n3 + } + return n, nil +} diff --git a/registry/registry.go b/registry/registry.go index 78e4b7b..d93bd6e 100644 --- a/registry/registry.go +++ b/registry/registry.go @@ -1,55 +1,45 @@ -package registry - -import "github.com/Tnze/go-mc/nbt" - -type Registry[E any] struct { - Type string `nbt:"type"` - Value []Entry[E] `nbt:"value"` -} - -type Entry[E any] struct { - Name string `nbt:"name"` - ID int32 `nbt:"id"` - Element E `nbt:"element"` -} - -func (r *Registry[E]) Find(name string) (int32, *E) { - for i := range r.Value { - if r.Value[i].Name == name { - return int32(i), &r.Value[i].Element - } - } - return -1, nil -} - -func (r *Registry[E]) FindByID(id int32) *E { - if id >= 0 && id < int32(len(r.Value)) && r.Value[id].ID == id { - return &r.Value[id].Element - } - for i := range r.Value { - if r.Value[i].ID == id { - return &r.Value[i].Element - } - } - return nil -} - -func (r *Registry[E]) Insert(name string, data E) { - entry := Entry[E]{ - Name: name, - ID: int32(len(r.Value)), - Element: data, - } - r.Value = append(r.Value, entry) -} - -func (r *Registry[E]) InsertWithNBT(name string, data nbt.RawMessage) error { - var elem E - if data.Type != 0 { - if err := data.UnmarshalDisallowUnknownField(&elem); err != nil { - return err - } - } - r.Insert(name, elem) - return nil -} +package registry + +type Registry[E any] struct { + keys map[string]int32 + values []E + indices map[*E]int32 +} + +func NewRegistry[E any]() Registry[E] { + return Registry[E]{ + keys: make(map[string]int32), + values: make([]E, 0, 256), + indices: make(map[*E]int32), + } +} + +func (r *Registry[E]) Get(key string) (int32, *E) { + id, ok := r.keys[key] + if !ok { + return -1, nil + } + return id, &r.values[id] +} + +func (r *Registry[E]) GetByID(id int32) *E { + if id >= 0 && id < int32(len(r.values)) { + return &r.values[id] + } + return nil +} + +func (r *Registry[E]) Put(name string, data E) (id int32, val *E) { + id = int32(len(r.values)) + r.keys[name] = id + r.values = append(r.values, data) + val = &r.values[id] + r.indices[val] = id + return +} + +func (r *Registry[E]) Clear() { + r.keys = make(map[string]int32) + r.values = r.values[:0] + r.indices = make(map[*E]int32) +}