diff --git a/client/client.go b/client/client.go index 16de82b..918d83e 100644 --- a/client/client.go +++ b/client/client.go @@ -3,7 +3,6 @@ package client import ( "net" - "github.com/admin-else/strom/event" "github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto_base" ) @@ -27,11 +26,8 @@ func Connect(addr string) (ret *proto.Conn, err error) { // when using this function. // You must close the connection when you're done with it func ConnectVersionLess(addr string) (ret *proto.Conn, err error) { - ret = &proto.Conn{} - ret.SetState(proto_base.Handshaking) - ret.SetCompressionThreshold(-1) + ret = proto.NewConn() ret.Actor = proto_base.Client - ret.Loop = event.NewLoop() ret.Conn, err = net.Dial("tcp", addr) if err != nil { return diff --git a/data/registry/1.21.11.nbt b/data/registry/1.21.11.nbt index 5d257b0..8ae435d 100644 Binary files a/data/registry/1.21.11.nbt and b/data/registry/1.21.11.nbt differ diff --git a/proto/connection.go b/proto/connection.go index b9f0d23..b3573e3 100644 --- a/proto/connection.go +++ b/proto/connection.go @@ -37,6 +37,7 @@ var ( type LoginTick struct{} var LatestVersion = proto_generated.SupportedVersions[len(proto_generated.SupportedVersions)-1] +var EarliestVersion = proto_generated.SupportedVersions[len(proto_generated.SupportedVersions)-1] // UnCodablePacket represents a packet that could not be decoded. type UnCodablePacket struct { @@ -230,7 +231,8 @@ func (c *Conn) Receive() (packet proto_base.EncodeDecodeAble, err error) { packet = reflect.New(reflect.TypeOf(i.Type).Elem()).Interface().(proto_base.EncodeDecodeAble) debugPrint := slog.Default().Enabled(context.Background(), slog.LevelDebug) && slices.ContainsFunc(c.DebugPrintPackets, func(s string) bool { return strings.Contains(i.Name, s) }) - if !c.IsTypeRegistered(reflect.TypeOf(packet)) && !debugPrint { + isListenerRegistered := c.IsTypeRegistered(reflect.TypeOf(packet)) + if !isListenerRegistered && !debugPrint { packet = &UnCodablePacket{Err: NoHandlerRegisteredErr, Data: packetBytes, Direction: c.Actor.ReceiveDirection()} return } @@ -246,7 +248,19 @@ func (c *Conn) Receive() (packet proto_base.EncodeDecodeAble, err error) { return } if debugPrint { - slog.Debug("recv", "packet", fmt.Sprintf("%#v", packet)) + slog.Debug("recv", "packet", fmt.Sprintf("%#v", packet), "isListenerRegistered", isListenerRegistered) } return } + +func NewConn() (ret *Conn) { + ret = &Conn{} + ret.SetState(proto_base.Handshaking) + ret.SetCompressionThreshold(-1) + err := ret.SetVersion(EarliestVersion) + if err != nil { + panic(err) + } + ret.Loop = event.NewLoop() + return +} diff --git a/proto/packet_lookup.go b/proto/packet_lookup.go index f0a1c11..b4c8ade 100644 --- a/proto/packet_lookup.go +++ b/proto/packet_lookup.go @@ -73,3 +73,12 @@ func LookupPacketInfoByNameProtocolVersionAndState(name string, version int32, s } return } + +func LookupPacketInfoByNameProtocolVersionStateAndDirection(name string, version int32, state proto_base.State, direction proto_base.Direction) (p proto_base.PacketInfo, ok bool) { + for _, p := range proto_generated.Packets { + if state == p.State && p.Name == name && p.ProtocolVersion == version && p.Direction == direction { + return p, true + } + } + return +} diff --git a/proto/smart_convert.go b/proto/smart_convert.go index f6859f3..d41e575 100644 --- a/proto/smart_convert.go +++ b/proto/smart_convert.go @@ -88,7 +88,11 @@ func (c *Conn) RegisterCriticalUntil(h any, until string) { func (c *Conn) registerUntil(h any, until string, critical bool) { eventType, hv := event.ValidateHandler(h) - c.RegisterDirect(eventType, hv) + if critical { + c.RegisterDirect(eventType, hv) + } else { + c.RegisterCustomType(eventType, hv) + } if !eventType.Implements(reflect.TypeFor[proto_base.EncodeDecodeAble]()) { panic("expected method with argument that implements proto_base.EncodeDecodeAble") } @@ -109,7 +113,7 @@ func (c *Conn) registerUntil(h any, until string, critical bool) { panic("protocol version not found") } var newPacketInfo proto_base.PacketInfo - newPacketInfo, found = LookupPacketInfoByNameProtocolVersionAndState(packetInfo.Name, versionInfo.Version, packetInfo.State) + newPacketInfo, found = LookupPacketInfoByNameProtocolVersionStateAndDirection(packetInfo.Name, versionInfo.Version, packetInfo.State, packetInfo.Direction) if !found { panic("packet not found") } diff --git a/proto/smart_convert_test.go b/proto/smart_convert_test.go index a4bfd4f..b7f375b 100644 --- a/proto/smart_convert_test.go +++ b/proto/smart_convert_test.go @@ -5,6 +5,7 @@ import ( "testing" "github.com/admin-else/strom/proto" + "github.com/admin-else/strom/proto_generated/v1_21_11" "github.com/admin-else/strom/proto_generated/v1_21_8" "github.com/admin-else/strom/proto_generated/v1_21_9" ) @@ -29,3 +30,19 @@ func TestCanSmartConvertTags(t *testing.T) { ret := proto.SmartConvert(reflect.ValueOf(packet), targetType) t.Logf("%#v", ret) } + +func TestRegisterUntilLatest(t *testing.T) { + conn := proto.NewConn() + ok := false + conn.RegisterCriticalUntilLatest(func(p *v1_21_8.ConfigurationToServerPacketFinishConfiguration) error { + ok = true + return nil + }) + err := conn.Fire(&v1_21_11.ConfigurationToServerPacketFinishConfiguration{}) + if err != nil { + t.Errorf("fire failed err: %v", err) + } + if !ok { + t.Errorf("handler not called") + } +} diff --git a/server/config_server.go b/server/config_server.go index 6d928f5..ab39766 100644 --- a/server/config_server.go +++ b/server/config_server.go @@ -1,9 +1,6 @@ package server import ( - "fmt" - "log/slog" - "github.com/admin-else/strom/data" "github.com/admin-else/strom/event" "github.com/admin-else/strom/nbt" @@ -14,24 +11,45 @@ import ( type ConfigServer struct { *proto.Conn -} - -func (c *ConfigServer) Default(event event.Anything) (err error) { - slog.Debug("Config server", "packet", fmt.Sprintf("%#v", event.Val)) - return + registryData map[string]any } func ServeConfig(c *proto.Conn) (err error) { + cs := &ConfigServer{Conn: c} n, err := data.LoadRegistry(c.Version) if err != nil { return } - for _, p := range n.Value.(map[string]any)["Registries"].([]any) { + err = c.Send(&v1_21_8.ConfigurationToClientPacketFeatureFlags{Features: []string{"minecraft:vanilla"}}) + if err != nil { + return + } + cs.registryData = n.Value.(map[string]any) + packet := &v1_21_8.ConfigurationToClientPacketCommonSelectKnownPacks{} + for _, pAny := range cs.registryData["KnownPacks"].([]any) { + p := pAny.(map[string]any) + packet.Packs = append(packet.Packs, struct { + Namespace string + Id string + Version string + }{p["Namespace"].(string), p["Id"].(string), p["Version"].(string)}) + } + err = c.Send(packet) + if err != nil { + return + } + cs.RegisterCriticalUntilLatest(cs.OnSelectKnownPacksResponse) + cs.RegisterCriticalUntilLatest(cs.OnFinishConfiguration) + return cs.StartConn() +} + +func (c *ConfigServer) OnSelectKnownPacksResponse(_ *v1_21_8.ConfigurationToServerPacketCommonSelectKnownPacks) (err error) { + for _, p := range c.registryData["Registries"].([]any) { packet := &v1_21_8.ConfigurationToClientPacketRegistryData{Id: p.(map[string]any)["Id"].(string)} for _, entry := range p.(map[string]any)["Entries"].([]any) { entryTyped := entry.(map[string]any) valAny, ok := entryTyped["Value"] - var val *nbt.Anon + var val *nbt.Anon = nil if ok { val = &nbt.Anon{Value: valAny} } @@ -46,7 +64,7 @@ func ServeConfig(c *proto.Conn) (err error) { } } tagsPacket := &v1_21_8.ConfigurationToClientPacketTags{} - for _, p := range n.Value.(map[string]any)["Tags"].([]any) { + for _, p := range c.registryData["Tags"].([]any) { p := p.(map[string]any) tags := v1_21_8.Tags{} for _, entry := range p["Entries"].([]any) { @@ -69,8 +87,7 @@ func ServeConfig(c *proto.Conn) (err error) { return } err = c.Send(&v1_21_8.ConfigurationToClientPacketFinishConfiguration{}) - cs := &ConfigServer{c} - return cs.StartLoop() + return } func (c *ConfigServer) OnFinishConfiguration(_ *v1_21_8.ConfigurationToServerPacketFinishConfiguration) (err error) { diff --git a/server/server.go b/server/server.go index af5b3df..b053cbb 100644 --- a/server/server.go +++ b/server/server.go @@ -5,22 +5,17 @@ import ( "log/slog" "net" - "github.com/admin-else/strom/event" "github.com/admin-else/strom/proto" "github.com/admin-else/strom/proto_base" "github.com/admin-else/strom/text" ) func Servee(c net.Conn) (ret *proto.Conn) { - ret = &proto.Conn{} - _ = ret.SetVersion("1.21.8") // cant fail - ret.SetState(proto_base.Handshaking) - ret.SetCompressionThreshold(-1) + ret = proto.NewConn() ret.Actor = proto_base.Servee ret.Conn = c ret.R = c ret.W = c - ret.Loop = event.NewLoop() return } diff --git a/tools/registry_data_hunter/main.go b/tools/registry_data_hunter/main.go index f6e897a..94c5500 100644 --- a/tools/registry_data_hunter/main.go +++ b/tools/registry_data_hunter/main.go @@ -70,6 +70,16 @@ func (p *Proxy) OnFinishConfiguration(_ *v1_21_8.ConfigurationToClientPacketFini return } +func (p *Proxy) OnSelectKnownPacks(data *v1_21_8.ConfigurationToClientPacketCommonSelectKnownPacks) (err error) { + var entries []any + for _, entry := range data.Packs { + e := map[string]any{"Namespace": entry.Namespace, "Id": entry.Id, "Version": entry.Version} + entries = append(entries, e) + } + p.Data.Value.(map[string]any)["KnownPacks"] = entries + return +} + func (p *Proxy) OnData(data *v1_21_8.ConfigurationToClientPacketRegistryData) (err error) { d := p.Data.Value.(map[string]any)["Registries"].([]any) var entries []any @@ -118,6 +128,7 @@ func handleClient(c *proto.Conn) (err error) { p.Servee.RegisterCritical(p.OnAnything) p.Client.RegisterCriticalUntilLatest(p.OnData) p.Client.RegisterCriticalUntilLatest(p.OnTags) + p.Client.RegisterCriticalUntilLatest(p.OnSelectKnownPacks) p.Client.RegisterCriticalUntilLatest(p.OnFinishConfiguration) go func() {