From 7ec8b6883ee51e21486487ad0329b0c500d1decb Mon Sep 17 00:00:00 2001 From: Ruphane <24724395+LNSSPsd@users.noreply.github.com> Date: Fri, 6 Jan 2023 23:35:48 -0800 Subject: [PATCH 1/4] Initial support for NEMC 2.5 --- fastbuilder/core/core.go | 91 +------------ fastbuilder/uqHolder/main.go | 7 +- go.sum | 2 + minecraft/LICENSE | 21 +++ minecraft/NOTE | 3 + minecraft/conn.go | 30 ++--- minecraft/dial.go | 84 +++++------- minecraft/game_data.go | 3 - minecraft/listener.go | 6 +- minecraft/nbt/decode.go | 32 ++--- minecraft/nbt/doc.go | 2 +- minecraft/nbt/dump.go | 6 +- minecraft/nbt/encode.go | 15 +-- minecraft/protocol/block.go | 2 +- minecraft/protocol/command.go | 15 ++- minecraft/protocol/game_rule.go | 2 +- minecraft/protocol/info.go | 5 +- minecraft/protocol/io.go | 10 +- minecraft/protocol/item.go | 4 +- minecraft/protocol/login/data.go | 4 +- minecraft/protocol/login/request.go | 25 ++-- minecraft/protocol/packet/actor_event.go | 3 + minecraft/protocol/packet/add_actor.go | 2 +- minecraft/protocol/packet/add_item_actor.go | 2 +- minecraft/protocol/packet/add_player.go | 8 +- .../protocol/packet/add_volume_entity.go | 13 +- .../protocol/packet/adventure_settings.go | 2 +- minecraft/protocol/packet/agent_action.go | 56 ++++++++ minecraft/protocol/packet/animate_entity.go | 1 - minecraft/protocol/packet/block_actor_data.go | 4 +- .../protocol/packet/change_mob_property.go | 46 +++++++ minecraft/protocol/packet/command_request.go | 1 + .../packet/correct_player_move_prediction.go | 2 +- minecraft/protocol/packet/dimension_data.go | 38 ++++++ minecraft/protocol/packet/id.go | 5 +- minecraft/protocol/packet/level_event.go | 2 + .../protocol/packet/level_sound_event.go | 48 +++++++ minecraft/protocol/packet/npc_dialogue.go | 8 +- minecraft/protocol/packet/pool.go | 5 +- minecraft/protocol/packet/py_rpc.go | 37 ------ .../protocol/packet/remove_volume_entity.go | 4 + minecraft/protocol/packet/set_actor_data.go | 2 +- .../protocol/packet/set_player_game_type.go | 2 + .../protocol/packet/spawn_particle_effect.go | 16 +++ minecraft/protocol/packet/start_game.go | 6 +- .../structure_template_data_response.go | 2 +- minecraft/protocol/packet/sub_chunk.go | 120 +++++++++--------- .../protocol/packet/sub_chunk_request.go | 4 +- .../protocol/packet/sync_actor_property.go | 2 +- .../packet/ticking_areas_load_status.go | 24 ++++ .../protocol/packet/update_attributes.go | 2 - minecraft/protocol/packet/update_block.go | 8 +- minecraft/protocol/reader.go | 23 ++-- minecraft/protocol/skin.go | 8 +- minecraft/protocol/sub_chunk.go | 2 +- minecraft/protocol/world.go | 30 +++++ minecraft/protocol/writer.go | 14 +- minecraft/resource/pack.go | 11 +- minecraft/text/colour.go | 27 ++-- mirror/io/assembler/assembler.go | 15 +-- omega/utils/pkt_mapping.go | 1 - 61 files changed, 573 insertions(+), 402 deletions(-) create mode 100644 minecraft/LICENSE create mode 100644 minecraft/NOTE create mode 100644 minecraft/protocol/packet/agent_action.go create mode 100644 minecraft/protocol/packet/change_mob_property.go create mode 100644 minecraft/protocol/packet/dimension_data.go delete mode 100644 minecraft/protocol/packet/py_rpc.go create mode 100644 minecraft/protocol/packet/ticking_areas_load_status.go create mode 100644 minecraft/protocol/world.go diff --git a/fastbuilder/core/core.go b/fastbuilder/core/core.go index 33f037735..9cfe63296 100644 --- a/fastbuilder/core/core.go +++ b/fastbuilder/core/core.go @@ -5,13 +5,11 @@ import ( "fmt" "time" "bufio" - "bytes" "strings" "runtime" "runtime/debug" "path/filepath" "encoding/json" - "encoding/binary" fbtask "phoenixbuilder/fastbuilder/task" "phoenixbuilder/omega/suggest" script_bridge "phoenixbuilder/fastbuilder/script_engine/bridge" @@ -167,7 +165,7 @@ func InitClient(env *environment.PBEnvironment) { ), // EnableClientCache: true, } - cconn, err := dialer.Dial("raknet", "") + cconn, err := dialer.Dial("raknet") if err != nil { pterm.Error.Println(err) @@ -195,7 +193,7 @@ func InitClient(env *environment.PBEnvironment) { }) env.UQHolder = uqHolder.NewUQHolder(conn.GameData().EntityRuntimeID) env.UQHolder.(*uqHolder.UQHolder).UpdateFromConn(conn) - env.UQHolder.(*uqHolder.UQHolder).CurrentTick = uint64(time.Now().Sub(conn.GameData().ConnectTime).Milliseconds()) / 50 + env.UQHolder.(*uqHolder.UQHolder).CurrentTick = 0 if args.ShouldEnableOmegaSystem() { _, cb:=embed.EnableOmegaSystem(env) @@ -207,7 +205,7 @@ func InitClient(env *environment.PBEnvironment) { functionHolder := env.FunctionHolder.(*function.FunctionHolder) function.InitInternalFunctions(functionHolder) fbtask.InitTaskStatusDisplay(env) - move.ConnectTime = conn.GameData().ConnectTime + move.ConnectTime = time.Time{} move.Position = conn.GameData().PlayerPosition move.Pitch = conn.GameData().Pitch move.Yaw = conn.GameData().Yaw @@ -329,9 +327,10 @@ func EnterWorkerThread(env *environment.PBEnvironment, breaker chan struct{}) { chunkAssembler := assembler.NewAssembler(assembler.REQUEST_AGGRESSIVE, time.Second*5) // max 100 chunk request per second - chunkAssembler.CreateRequestScheduler(func(pk *packet.SubChunkRequest) { + /*chunkAssembler.CreateRequestScheduler(func(pk *packet.SubChunkRequest) { conn.WritePacket(pk) - }) + })*/ + fmt.Printf("WARNING: TODO: Dump runtime id table, for what chunk loading is currently stubbed\n") // currentChunkConstructor := &world_provider.ChunkConstructor{} for { if(breaker!=nil) { @@ -379,84 +378,6 @@ func EnterWorkerThread(env *environment.PBEnvironment, breaker chan struct{}) { // pterm.Info.Println("ClientCacheStatus", p) // case *packet.ClientCacheBlobStatus: // pterm.Info.Println("ClientCacheBlobStatus", p) - case *packet.PyRpc: - if args.NoPyRpc() { - break - } - //fmt.Printf("PyRpc!\n") - if strings.Contains(string(p.Content), "GetLoadingTime") { - //fmt.Printf("GetLoadingTime!!\n") - uid := conn.IdentityData().Uid - num := uid&255 ^ (uid&65280)>>8 - curTime := time.Now().Unix() - num = curTime&3 ^ (num&7)<<2 ^ (curTime&252)<<3 ^ (num&248)<<8 - numcont := make([]byte, 2) - binary.BigEndian.PutUint16(numcont, uint16(num)) - conn.WritePacket(&packet.PyRpc{ - Content: []byte{0x82, 0xc4, 0x8, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x5f, 0xc4, 0x5, 0x74, 0x75, 0x70, 0x6c, 0x65, 0xc4, 0x5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x93, 0xc4, 0x12, 0x53, 0x65, 0x74, 0x6c, 0x6f, 0x61, 0x64, 0x4c, 0x6f, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x82, 0xc4, 0x8, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x5f, 0xc4, 0x5, 0x74, 0x75, 0x70, 0x6c, 0x65, 0xc4, 0x5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x91, 0xcd, numcont[0], numcont[1], 0xc0}, - }) - // Good job, netease, you wasted 3 days of my idle time - // (-Ruphane) - - // See analyze/nemcfix/final.py for its python version - // and see analyze/ for how I did it. - //tellraw(conn, "Welcome to FastBuilder!") - //tellraw(conn, fmt.Sprintf("Operator: %s", env.RespondUser)) - //sendCommand("testforblock ~ ~ ~ air", zeroId, conn) - } else if strings.Contains(string(p.Content), "check_server_contain_pet") { - //fmt.Printf("Checkpet!!\n") - - // Pet req - /*conn.WritePacket(&packet.PyRpc { - Content: bytes.Join([][]byte{[]byte{0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x93,0xc4,0xb,0x4d,0x6f,0x64,0x45,0x76,0x65,0x6e,0x74,0x43,0x32,0x53,0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x94,0xc4,0x9,0x4d,0x69,0x6e,0x65,0x63,0x72,0x61,0x66,0x74,0xc4,0x3,0x70,0x65,0x74,0xc4,0x12,0x73,0x75,0x6d,0x6d,0x6f,0x6e,0x5f,0x70,0x65,0x74,0x5f,0x72,0x65,0x71,0x75,0x65,0x73,0x74,0x87,0xc4,0x13,0x61,0x6c,0x6c,0x6f,0x77,0x5f,0x73,0x74,0x65,0x70,0x5f,0x6f,0x6e,0x5f,0x62,0x6c,0x6f,0x63,0x6b,0xc2,0xc4,0xb,0x61,0x76,0x6f,0x69,0x64,0x5f,0x6f,0x77,0x6e,0x65,0x72,0xc3,0xc4,0x7,0x73,0x6b,0x69,0x6e,0x5f,0x69,0x64,0xcd,0x27,0x11,0xc4,0x9,0x70,0x6c,0x61,0x79,0x65,0x72,0x5f,0x69,0x64,0xc4}, - []byte{byte(len(runtimeid))}, - []byte(runtimeid), - []byte{0xc4,0x6,0x70,0x65,0x74,0x5f,0x69,0x64,0x1,0xc4,0xa,0x6d,0x6f,0x64,0x65,0x6c,0x5f,0x6e,0x61,0x6d,0x65,0xc4,0x14,0x74,0x79,0x5f,0x79,0x75,0x61,0x6e,0x73,0x68,0x65,0x6e,0x67,0x68,0x75,0x6c,0x69,0x5f,0x30,0x5f,0x30,0xc4,0x4,0x6e,0x61,0x6d,0x65,0xc4,0xc,0xe6,0x88,0x91,0xe7,0x9a,0x84,0xe4,0xbc,0x99,0xe4,0xbc,0xb4,0xc0}, - },[]byte{}), - })*/ - - } else if strings.Contains(string(p.Content), "summon_pet_response") { - //fmt.Printf("summonpetres\n") - /*conn.WritePacket(&packet.PyRpc { - Content: []byte{0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x93,0xc4,0x19,0x61,0x72,0x65,0x6e,0x61,0x47,0x61,0x6d,0x65,0x50,0x6c,0x61,0x79,0x65,0x72,0x46,0x69,0x6e,0x69,0x73,0x68,0x4c,0x6f,0x61,0x64,0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x90,0xc0}, - }) - conn.WritePacket(&packet.PyRpc { - Content: bytes.Join([][]byte{[]byte{0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x93,0xc4,0xb,0x4d,0x6f,0x64,0x45,0x76,0x65,0x6e,0x74,0x43,0x32,0x53,0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x94,0xc4,0x9,0x4d,0x69,0x6e,0x65,0x63,0x72,0x61,0x66,0x74,0xc4,0xe,0x76,0x69,0x70,0x45,0x76,0x65,0x6e,0x74,0x53,0x79,0x73,0x74,0x65,0x6d,0xc4,0xc,0x50,0x6c,0x61,0x79,0x65,0x72,0x55,0x69,0x49,0x6e,0x69,0x74,0xc4}, - []byte{byte(len(runtimeid))}, - []byte(runtimeid), - []byte{0xc0}, - },[]byte{}), - })*/ - /*conn.WritePacket(&packet.PyRpc { - Content: []byte{0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x93,0xc4,0x1f,0x43,0x6c,0x69,0x65,0x6e,0x74,0x4c,0x6f,0x61,0x64,0x41,0x64,0x64,0x6f,0x6e,0x73,0x46,0x69,0x6e,0x69,0x73,0x68,0x65,0x64,0x46,0x72,0x6f,0x6d,0x47,0x61,0x63,0x82,0xc4,0x8,0x5f,0x5f,0x74,0x79,0x70,0x65,0x5f,0x5f,0xc4,0x5,0x74,0x75,0x70,0x6c,0x65,0xc4,0x5,0x76,0x61,0x6c,0x75,0x65,0x90,0xc0}, - })*/ - } else if strings.Contains(string(p.Content), "GetStartType") { - // 2021-12-22 10:51~11:55 - // Thank netease for wasting my time again ;) - encData := p.Content[68 : len(p.Content)-1] - client := env.FBAuthClient.(*fbauth.Client) - response := client.TransferData(string(encData), fmt.Sprintf("%s", env.Uid)) - conn.WritePacket(&packet.PyRpc{ - Content: bytes.Join([][]byte{[]byte{0x82, 0xc4, 0x8, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x5f, 0xc4, 0x5, 0x74, 0x75, 0x70, 0x6c, 0x65, 0xc4, 0x5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x93, 0xc4, 0xc, 0x53, 0x65, 0x74, 0x53, 0x74, 0x61, 0x72, 0x74, 0x54, 0x79, 0x70, 0x65, 0x82, 0xc4, 0x8, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x5f, 0xc4, 0x5, 0x74, 0x75, 0x70, 0x6c, 0x65, 0xc4, 0x5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x91, 0xc4}, - []byte{byte(len(response))}, - []byte(response), - []byte{0xc0}, - }, []byte{}), - }) - } else if strings.Contains(string(p.Content), "GetMCPCheckNum") { - firstArgLenB := p.Content[69:71] - firstArgLen := binary.BigEndian.Uint16(firstArgLenB) - secondArgLen := uint16(p.Content[72+firstArgLen]) - secondArg := string(p.Content[73+firstArgLen : 73+firstArgLen+secondArgLen]) - valM := utils.GetMD5(fmt.Sprintf("296<6puv?ol%sk", secondArg)) - conn.WritePacket(&packet.PyRpc{ - Content: bytes.Join([][]byte{[]byte{0x82, 0xc4, 0x8, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x5f, 0xc4, 0x5, 0x74, 0x75, 0x70, 0x6c, 0x65, 0xc4, 0x5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x93, 0xc4, 0xe, 0x53, 0x65, 0x74, 0x4d, 0x43, 0x50, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x82, 0xc4, 0x8, 0x5f, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x5f, 0xc4, 0x5, 0x74, 0x75, 0x70, 0x6c, 0x65, 0xc4, 0x5, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x91, 0xc4, 0x20}, - []byte(valM), - []byte{0xc0}, - }, []byte{}), - }) - } - break case *packet.StructureTemplateDataResponse: special_tasks.ExportWaiter <- p.StructureTemplate break diff --git a/fastbuilder/uqHolder/main.go b/fastbuilder/uqHolder/main.go index fc114c8f6..8f8067db1 100644 --- a/fastbuilder/uqHolder/main.go +++ b/fastbuilder/uqHolder/main.go @@ -534,7 +534,7 @@ func (uq *UQHolder) Update(pk packet.Packet) { // } //} // meaning not clear - case *packet.PlayerHotBar: + /*case *packet.PlayerHotBar: uq.PlayerHotBar = *p // not supported, plan to support case *packet.InventoryTransaction: @@ -559,8 +559,7 @@ func (uq *UQHolder) Update(pk packet.Packet) { // no need to support case *packet.PlayStatus: // no need to support - case *packet.PyRpc: - //not handled + */ default: if !uq.displayUnknownPackets { break @@ -582,7 +581,7 @@ func (uq *UQHolder) Update(pk packet.Packet) { func (uq *UQHolder) UpdateFromConn(conn *minecraft.Conn) { gd := conn.GameData() uq.BotUniqueID = gd.EntityUniqueID - uq.ConnectTime = gd.ConnectTime + uq.ConnectTime = time.Time{} // No longer needed uq.WorldName = gd.WorldName uq.WorldGameMode = gd.WorldGameMode uq.WorldDifficulty = uint32(gd.Difficulty) diff --git a/go.sum b/go.sum index decbef2db..945443c77 100644 --- a/go.sum +++ b/go.sum @@ -189,6 +189,8 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/minecraft/LICENSE b/minecraft/LICENSE new file mode 100644 index 000000000..19ea06705 --- /dev/null +++ b/minecraft/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 Sandertv + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/minecraft/NOTE b/minecraft/NOTE new file mode 100644 index 000000000..d5db72ca2 --- /dev/null +++ b/minecraft/NOTE @@ -0,0 +1,3 @@ +Codes in this directory are originally from [gophertunnel] +(https://github.com/Sandertv/gophertunnel), which is +licensed under the MIT license, see [LICENSE] for reference. \ No newline at end of file diff --git a/minecraft/conn.go b/minecraft/conn.go index f39984e54..49f854ba0 100644 --- a/minecraft/conn.go +++ b/minecraft/conn.go @@ -8,9 +8,8 @@ import ( "crypto/sha256" "encoding/base64" "fmt" - "io" - "log" - "net" + "github.com/google/uuid" + "github.com/sandertv/go-raknet" "phoenixbuilder/minecraft/internal" "phoenixbuilder/minecraft/nbt" "phoenixbuilder/minecraft/protocol" @@ -18,15 +17,15 @@ import ( "phoenixbuilder/minecraft/protocol/packet" "phoenixbuilder/minecraft/resource" "phoenixbuilder/minecraft/text" - "strings" - "sync" - "time" - - "github.com/google/uuid" - "github.com/sandertv/go-raknet" "go.uber.org/atomic" "gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2/jwt" + "io" + "log" + "net" + "strings" + "sync" + "time" ) // exemptedResourcePack is a resource pack that is exempted from being downloaded. These packs may be directly @@ -111,7 +110,7 @@ type Conn struct { resourcePacks []*resource.Pack // biomes is a map of biome definitions that the listener may hold. Each client will be sent these biome // definitions upon joining. - biomes map[string]interface{} + biomes map[string]any // texturePacksRequired specifies if clients that join must accept the texture pack in order for them to // be able to join the server. If they don't accept, they can only leave the server. texturePacksRequired bool @@ -126,9 +125,7 @@ type Conn struct { disconnectMessage atomic.String shieldID atomic.Int32 - - // PhoenixBuilder debug mode, which means this connection is fake - // and nothing will be sended or received from it. + DebugMode bool } @@ -356,10 +353,6 @@ func (conn *Conn) ReadPacket() (pk packet.Packet, err error) { func (conn *Conn) ReadPacketAndBytes() (pk packet.Packet, data []byte, err error) { if data, ok := conn.takeDeferredPacket(); ok { - // if data.h.PacketID != 67 { - // fmt.Println(data.h.PacketID) - // } - pk, err := data.decode(conn) if err != nil { conn.log.Println(err) @@ -1142,7 +1135,6 @@ func (conn *Conn) handleStartGame(pk *packet.StartGame) error { WorldGameMode: pk.WorldGameMode, ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory, Experiments: pk.Experiments, - ConnectTime: time.Now(), } for _, item := range pk.Items { if item.Name == "minecraft:shield" { @@ -1254,7 +1246,7 @@ func (conn *Conn) handlePlayStatus(pk *packet.PlayStatus) error { // handshake packet to the client and enables encryption after that. func (conn *Conn) enableEncryption(clientPublicKey *ecdsa.PublicKey) error { signer, _ := jose.NewSigner(jose.SigningKey{Key: conn.privateKey, Algorithm: jose.ES384}, &jose.SignerOptions{ - ExtraHeaders: map[jose.HeaderKey]interface{}{"x5u": login.MarshalPublicKey(&conn.privateKey.PublicKey)}, + ExtraHeaders: map[jose.HeaderKey]any{"x5u": login.MarshalPublicKey(&conn.privateKey.PublicKey)}, }) // We produce an encoded JWT using the header and payload above, then we send the JWT in a ServerToClient- // Handshake packet so that the client can initialise encryption. diff --git a/minecraft/dial.go b/minecraft/dial.go index 0777a81a6..e0a11397d 100644 --- a/minecraft/dial.go +++ b/minecraft/dial.go @@ -1,7 +1,6 @@ package minecraft import ( - "fmt" "bytes" "context" "crypto/ecdsa" @@ -9,23 +8,23 @@ import ( "crypto/rand" "crypto/x509" "encoding/base64" - "io/ioutil" - "log" - rand2 "math/rand" - "net" + "github.com/google/uuid" + "github.com/sandertv/go-raknet" "phoenixbuilder/minecraft/internal/resource" "phoenixbuilder/minecraft/protocol" "phoenixbuilder/minecraft/protocol/login" "phoenixbuilder/minecraft/protocol/packet" + "io" + "log" + rand2 "math/rand" + "net" + "os" "strconv" "strings" "time" - - "github.com/google/uuid" - "github.com/sandertv/go-raknet" ) -type GameAuthenticator interface { +type Authenticator interface { GetAccess(publicKey []byte) (address string, chainInfo string, err error) } @@ -43,8 +42,10 @@ type Dialer struct { // XUID of the player. // The IdentityData object is obtained using Minecraft auth if Email and Password are set. If not, the // object provided here is used, or a default one if left empty. - IdentityData login.IdentityData - Authenticator GameAuthenticator + IdentityData login.IdentityData + + // Authenticator towards netease's server + Authenticator // PacketFunc is called whenever a packet is read from or written to the connection returned when using // Dialer.Dial(). It includes packets that are otherwise covered in the connection sequence, such as the @@ -56,6 +57,12 @@ type Dialer struct { // server will send chunks as blobs, which may be saved by the client so that chunks don't have to be // transmitted every time, resulting in less network transmission. EnableClientCache bool + + // KeepXBLIdentityData, if set to true, enables passing XUID and title ID to the target server + // if the authentication token is not set. This is technically not valid and some servers might kick + // the client when an XUID is present without logging in. + // For getting this to work with BDS, authentication should be disabled. + KeepXBLIdentityData bool } // Dial dials a Minecraft connection to the address passed over the network passed. The network is typically @@ -63,9 +70,9 @@ type Dialer struct { // // A zero value of a Dialer struct is used to initiate the connection. A custom Dialer may be used to specify // additional behaviour. -func Dial(network, address string) (*Conn, error) { +func Dial(network string) (*Conn, error) { var d Dialer - return d.Dial(network, address) + return d.Dial(network) } // DialTimeout dials a Minecraft connection to the address passed over the network passed. The network is @@ -88,7 +95,7 @@ func DialContext(ctx context.Context, network string) (*Conn, error) { // Dial dials a Minecraft connection to the address passed over the network passed. The network is typically // "raknet". A Conn is returned which may be used to receive packets from and send packets to. -func (d Dialer) Dial(network, address string) (*Conn, error) { +func (d Dialer) Dial(network string) (*Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*30) defer cancel() return d.DialContext(ctx, network) @@ -108,45 +115,23 @@ func (d Dialer) DialTimeout(network string, timeout time.Duration) (*Conn, error // If a connection is not established before the context passed is cancelled, DialContext returns an error. func (d Dialer) DialContext(ctx context.Context, network string) (conn *Conn, err error) { key, _ := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - data, _ := x509.MarshalPKIXPublicKey(&key.PublicKey) - address, chainData, err := d.Authenticator.GetAccess(data) + + armoured_key, _ := x509.MarshalPKIXPublicKey(&key.PublicKey) + + address, chainData, err := d.Authenticator.GetAccess(armoured_key) if err != nil { return nil, err } - - // var chainData string - // if d.ServerCode != "" { - // data, _ := x509.MarshalPKIXPublicKey(&key.PublicKey) - // pubKeyData := base64.StdEncoding.EncodeToString(data) - // chainAddr, code, err := d.Client.Auth(d.ServerCode, d.Password, pubKeyData, d.Token) - // chainAndAddr := strings.Split(chainAddr, "|") - - // if err != nil { - // if code == -3 { - // homedir, err := os.UserHomeDir() - // if err != nil { - // fmt.Println(I18n.T(I18n.Warning_UserHomeDir)) - // homedir = "." - // } - // fbconfigdir := filepath.Join(homedir, ".config/fastbuilder") - // os.MkdirAll(fbconfigdir, 0755) - // token := filepath.Join(fbconfigdir, "fbtoken") - // os.Remove(token) - // } - // return nil, err - // } - // chainData = chainAndAddr[0] - // address = chainAndAddr[1] - // } - // if d.ErrorLog == nil { - // d.ErrorLog = log.New(os.Stderr, "", log.LstdFlags) - // } + + if d.ErrorLog == nil { + d.ErrorLog = log.New(os.Stderr, "", log.LstdFlags) + } var netConn net.Conn switch network { case "raknet": // If the network is specifically 'raknet', we use the raknet library to dial a RakNet connection. - dialer := raknet.Dialer{ErrorLog: log.New(ioutil.Discard, "", 0)} + dialer := raknet.Dialer{ErrorLog: log.New(io.Discard, "", 0)} var pong []byte pong, err = dialer.PingContext(ctx, address) if err != nil { @@ -180,10 +165,7 @@ func (d Dialer) DialContext(ctx context.Context, network string) (conn *Conn, er setAndroidData(&conn.clientData) request = login.Encode(chainData, conn.clientData, key) - identityData, _, _, err := login.Parse(request) - if err!=nil { - fmt.Printf("WARNING: Failed on login info parsing: %v\n", err) - } + identityData, _, _, _ := login.Parse(request) // If we got the identity data from Minecraft auth, we need to make sure we set it in the Conn too, as // we are not aware of the identity data ourselves yet. conn.identityData = identityData @@ -218,14 +200,14 @@ func listenConn(conn *Conn, logger *log.Logger, c chan struct{}) { packets, err := conn.dec.Decode() if err != nil { if !raknet.ErrConnectionClosed(err) { - fmt.Printf("error reading from dialer connection: %v\n", err) + logger.Printf("error reading from dialer connection: %v\n", err) } return } for _, data := range packets { loggedInBefore := conn.loggedIn if err := conn.receive(data); err != nil { - fmt.Printf("error: %v", err) + logger.Printf("error: %v", err) return } if !loggedInBefore && conn.loggedIn { diff --git a/minecraft/game_data.go b/minecraft/game_data.go index 2ad7b31f2..5523be5f0 100644 --- a/minecraft/game_data.go +++ b/minecraft/game_data.go @@ -3,7 +3,6 @@ package minecraft import ( "github.com/go-gl/mathgl/mgl32" "phoenixbuilder/minecraft/protocol" - "time" ) // GameData is a loose wrapper around a part of the data found in the StartGame packet. It holds data sent @@ -74,6 +73,4 @@ type GameData struct { // Experiments is a list of experiments enabled on the server side. These experiments are used to enable // disable experimental features. Experiments []protocol.ExperimentData - // The time when the client connected to the server. - ConnectTime time.Time } diff --git a/minecraft/listener.go b/minecraft/listener.go index ff6e7fefb..57027e4c7 100644 --- a/minecraft/listener.go +++ b/minecraft/listener.go @@ -10,7 +10,7 @@ import ( "phoenixbuilder/minecraft/protocol/packet" "phoenixbuilder/minecraft/resource" "go.uber.org/atomic" - "io/ioutil" + "io" "log" "net" "os" @@ -45,7 +45,7 @@ type ListenConfig struct { ResourcePacks []*resource.Pack // Biomes contains information about all biomes that the server has registered, which the client can use // to render the world more effectively. If these are nil, the default biome definitions will be used. - Biomes map[string]interface{} + Biomes map[string]any // TexturePacksRequired specifies if clients that join must accept the texture pack in order for them to // be able to join the server. If they don't accept, they can only leave the server. TexturePacksRequired bool @@ -83,7 +83,7 @@ func (cfg ListenConfig) Listen(network, address string) (*Listener, error) { switch network { case "raknet": - netListener, err = raknet.ListenConfig{ErrorLog: log.New(ioutil.Discard, "", 0)}.Listen(address) + netListener, err = raknet.ListenConfig{ErrorLog: log.New(io.Discard, "", 0)}.Listen(address) default: // Fall back to the standard net.Listen. netListener, err = net.Listen(network, address) diff --git a/minecraft/nbt/decode.go b/minecraft/nbt/decode.go index 0c2367f9f..297607717 100644 --- a/minecraft/nbt/decode.go +++ b/minecraft/nbt/decode.go @@ -32,7 +32,7 @@ func NewDecoderWithEncoding(r io.Reader, encoding Encoding) *Decoder { // Decode reads the next NBT object from the input stream and stores it into the pointer to an object passed. // See the Unmarshal docs for the conversion between NBT tags to Go types. -func (d *Decoder) Decode(v interface{}) error { +func (d *Decoder) Decode(v any) error { val := reflect.ValueOf(v) if val.Kind() != reflect.Ptr { return NonPointerTypeError{ActualType: val.Type()} @@ -49,19 +49,19 @@ func (d *Decoder) Decode(v interface{}) error { // // The Go value passed must be a pointer to a value. Anything else will return an error before decoding. // The following NBT tags are decoded in the Go value passed as such: -// TAG_Byte: byte/uint8(/interface{}) or bool -// TAG_Short: int16(/interface{}) -// TAG_Int: int32(/interface{}) -// TAG_Long: int64(/interface{}) -// TAG_Float: float32(/interface{}) -// TAG_Double: float64(/interface{}) -// TAG_ByteArray: [...]byte(/interface{}) (The value must be a byte array, not a slice) -// TAG_String: string(/interface{}) -// TAG_List: []interface{}(/interface{}) (The value type of the slice may vary. Depending on the type of +// TAG_Byte: byte/uint8(/any) or bool +// TAG_Short: int16(/any) +// TAG_Int: int32(/any) +// TAG_Long: int64(/any) +// TAG_Float: float32(/any) +// TAG_Double: float64(/any) +// TAG_ByteArray: [...]byte(/any) (The value must be a byte array, not a slice) +// TAG_String: string(/any) +// TAG_List: []any(/any) (The value type of the slice may vary. Depending on the type of // values in the List tag, it might be of the type of any of the other tags, such as []int64. -// TAG_Compound: struct{...}/map[string]interface{}(/interface{}) -// TAG_IntArray: [...]int32(/interface{}) (The value must be an int32 array, not a slice) -// TAG_LongArray: [...]int64(/interface{}) (The value must be an int64 array, not a slice) +// TAG_Compound: struct{...}/map[string]any(/any) +// TAG_IntArray: [...]int32(/any) (The value must be an int32 array, not a slice) +// TAG_LongArray: [...]int64(/any) (The value must be an int64 array, not a slice) // // Unmarshal returns an error if the data is decoded into a struct and the struct does not have all fields // that the matching TAG_Compound in the NBT has, in order to prevent the loss of data. For varying data, the @@ -71,13 +71,13 @@ func (d *Decoder) Decode(v interface{}) error { // Unmarshal accepts struct fields with the 'nbt' struct tag. The 'nbt' struct tag allows setting the name of // a field that some tag should be decoded in. Setting the struct tag to '-' means that field will never be // filled by the decoding of the data passed. -func Unmarshal(data []byte, v interface{}) error { +func Unmarshal(data []byte, v any) error { return UnmarshalEncoding(data, v, NetworkLittleEndian) } // UnmarshalEncoding decodes a slice of NBT data into a pointer to a Go values passed using the NBT encoding // passed. Its functionality is identical to that of Unmarshal, except that it allows a specific encoding. -func UnmarshalEncoding(data []byte, v interface{}, encoding Encoding) error { +func UnmarshalEncoding(data []byte, v any, encoding Encoding) error { buf := bytes.NewBuffer(data) return (&Decoder{Encoding: encoding, r: &offsetReader{ Reader: buf, @@ -95,7 +95,7 @@ var int64Type = reflect.TypeOf(int64(0)) // fieldMapPool is used to store maps holding the fields of a struct. These maps are cleared each time they // are put back into the pool, but are re-used simply so that they need not to be re-allocated each operation. var fieldMapPool = sync.Pool{ - New: func() interface{} { + New: func() any { return map[string]reflect.Value{} }, } diff --git a/minecraft/nbt/doc.go b/minecraft/nbt/doc.go index f3dfb2611..8234e5038 100644 --- a/minecraft/nbt/doc.go +++ b/minecraft/nbt/doc.go @@ -20,7 +20,7 @@ // string: TAG_String // []: TAG_List // struct{...}: TAG_Compound -// map[string]: TAG_Compound +// map[string]: TAG_Compound // // Structures decoded or encoded may have struct field tags in a comparable way to the JSON standard library. // The 'nbt' struct tag may be filled out the following ways: diff --git a/minecraft/nbt/dump.go b/minecraft/nbt/dump.go index 425d93d2f..b59172b08 100644 --- a/minecraft/nbt/dump.go +++ b/minecraft/nbt/dump.go @@ -17,7 +17,7 @@ import ( // If the serialised NBT data passed is not parsable using the encoding that was passed, an error is returned // and the resulting string will always be empty. func Dump(data []byte, encoding Encoding) (string, error) { - var m map[string]interface{} + var m map[string]any if err := UnmarshalEncoding(data, &m, encoding); err != nil { return "", fmt.Errorf("error decoding NBT: %v", err) } @@ -42,7 +42,7 @@ func (s *dumpState) indent() string { // encodeTagType encodes the type of the value passed to an NBT tag name. The way these are translated can be // found in the doc.go file. -func (s *dumpState) encodeTagType(val interface{}) string { +func (s *dumpState) encodeTagType(val any) string { if val == nil { return "nil" } @@ -90,7 +90,7 @@ func (s *dumpState) encodeTagType(val interface{}) string { // encodeTagValue encodes a value passed to a format in which they are displayed in the dump string. // encodeTagValue operates recursively: If lists or compounds are nested, encodeTagValue will include all // nested tags. -func (s *dumpState) encodeTagValue(val interface{}) string { +func (s *dumpState) encodeTagValue(val any) string { //noinspection SpellCheckingInspection const hexTable = "0123456789abcdef" diff --git a/minecraft/nbt/encode.go b/minecraft/nbt/encode.go index af80b19a2..c03521871 100644 --- a/minecraft/nbt/encode.go +++ b/minecraft/nbt/encode.go @@ -43,16 +43,11 @@ func NewEncoderWithEncoding(w io.Writer, encoding Encoding) *Encoder { // Encode encodes an object to NBT and writes it to the NBT output stream of the encoder. See the Marshal // docs for the conversion from Go types to NBT tags and special struct tags. -func (e *Encoder) Encode(v interface{}) error { +func (e *Encoder) Encode(v any) error { val := reflect.ValueOf(v) return e.marshal(val, "") } -func (e *Encoder) EncodeWithRootTag(v interface{}, root string) error { - val := reflect.ValueOf(v) - return e.marshal(val, root) -} - // Marshal encodes an object to its NBT representation and returns it as a byte slice. It uses the // NetworkLittleEndian NBT encoding. To use a specific encoding, use MarshalEncoding. // @@ -73,19 +68,19 @@ func (e *Encoder) EncodeWithRootTag(v interface{}, root string) error { // string: TAG_String // []: TAG_List // struct{...}: TAG_Compound -// map[string]: TAG_Compound +// map[string]: TAG_Compound // // Marshal accepts struct fields with the 'nbt' struct tag. The 'nbt' struct tag allows setting the name of // a field that some tag should be decoded in. Setting the struct tag to '-' means that field will never be // filled by the decoding of the data passed. Suffixing the 'nbt' struct tag with ',omitempty' will prevent // the field from being encoded if it is equal to its default value. -func Marshal(v interface{}) ([]byte, error) { +func Marshal(v any) ([]byte, error) { return MarshalEncoding(v, NetworkLittleEndian) } // MarshalEncoding encodes an object to its NBT representation and returns it as a byte slice. Its // functionality is identical to that of Marshal, except it accepts any NBT encoding. -func MarshalEncoding(v interface{}, encoding Encoding) ([]byte, error) { +func MarshalEncoding(v any, encoding Encoding) ([]byte, error) { b := bufferPool.Get().(*bytes.Buffer) err := (&Encoder{w: &offsetWriter{Writer: b, WriteByte: b.WriteByte}, Encoding: encoding}).Encode(v) data := append([]byte(nil), b.Bytes()...) @@ -99,7 +94,7 @@ func MarshalEncoding(v interface{}, encoding Encoding) ([]byte, error) { // bufferPool is a sync.Pool holding bytes.Buffers which are re-used for writing NBT, so that no new buffer // needs to be allocated for each write. var bufferPool = sync.Pool{ - New: func() interface{} { + New: func() any { return bytes.NewBuffer(make([]byte, 0, 64)) }, } diff --git a/minecraft/protocol/block.go b/minecraft/protocol/block.go index e55b47ae5..23d3e8516 100644 --- a/minecraft/protocol/block.go +++ b/minecraft/protocol/block.go @@ -9,7 +9,7 @@ type BlockEntry struct { // Name is the name of the custom block. Name string // Properties is a list of properties which, in combination with the name, specify a unique block. - Properties map[string]interface{} + Properties map[string]any } // Block reads a BlockEntry x from IO r. diff --git a/minecraft/protocol/command.go b/minecraft/protocol/command.go index 372d78268..452abb079 100644 --- a/minecraft/protocol/command.go +++ b/minecraft/protocol/command.go @@ -48,14 +48,15 @@ const ( CommandArgTypeWildcardInt = 5 CommandArgTypeOperator = 6 CommandArgTypeTarget = 7 - CommandArgTypeWildcardTarget = 8 + CommandArgTypeWildcardTarget = 9 CommandArgTypeFilepath = 16 - CommandArgTypeString = 32 - CommandArgTypePosition = 40 - CommandArgTypeMessage = 44 - CommandArgTypeRawText = 46 - CommandArgTypeJSON = 50 - CommandArgTypeCommand = 63 + CommandArgTypeString = 38 + CommandArgTypeBlockPosition = 46 + CommandArgTypePosition = 47 + CommandArgTypeMessage = 50 + CommandArgTypeRawText = 52 + CommandArgTypeJSON = 56 + CommandArgTypeCommand = 69 ) const ( // ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not, diff --git a/minecraft/protocol/game_rule.go b/minecraft/protocol/game_rule.go index 65ac98d36..7711bab7e 100644 --- a/minecraft/protocol/game_rule.go +++ b/minecraft/protocol/game_rule.go @@ -11,7 +11,7 @@ type GameRule struct { // CanBeModifiedByPlayer ... CanBeModifiedByPlayer bool // Value ... - Value interface{} + Value any } // GameRules reads a map of game rules from Reader r. It sets one of the types 'bool', 'float32' or 'uint32' diff --git a/minecraft/protocol/info.go b/minecraft/protocol/info.go index 5cc14b778..cfb2c4a11 100644 --- a/minecraft/protocol/info.go +++ b/minecraft/protocol/info.go @@ -2,8 +2,7 @@ package protocol const ( // CurrentProtocol is the current protocol version for the version below. - CurrentProtocol = 475 + CurrentProtocol = 504 // CurrentVersion is the current version of Minecraft as supported by the `packet` package. - CurrentVersion = "1.18.10" - // 475 -> 1.18.0. + CurrentVersion = "1.18.30" ) diff --git a/minecraft/protocol/io.go b/minecraft/protocol/io.go index fb685bc23..7933e54f4 100644 --- a/minecraft/protocol/io.go +++ b/minecraft/protocol/io.go @@ -37,15 +37,15 @@ type IO interface { SubChunkPos(x *SubChunkPos) ByteFloat(x *float32) Bytes(p *[]byte) - NBT(m *map[string]interface{}, encoding nbt.Encoding) - NBTList(m *[]interface{}, encoding nbt.Encoding) + NBT(m *map[string]any, encoding nbt.Encoding) + NBTList(m *[]any, encoding nbt.Encoding) UUID(x *uuid.UUID) VarRGBA(x *color.RGBA) - EntityMetadata(x *map[uint32]interface{}) + EntityMetadata(x *map[uint32]any) Item(x *ItemStack) ItemInstance(i *ItemInstance) MaterialReducer(x *MaterialReducer) - UnknownEnumOption(value interface{}, enum string) - InvalidValue(value interface{}, forField, reason string) + UnknownEnumOption(value any, enum string) + InvalidValue(value any, forField, reason string) } diff --git a/minecraft/protocol/item.go b/minecraft/protocol/item.go index acfcb772c..dd851e69d 100644 --- a/minecraft/protocol/item.go +++ b/minecraft/protocol/item.go @@ -24,7 +24,7 @@ type ItemStack struct { // Count is the count of items that the item stack holds. Count uint16 // NBTData is a map that is serialised to its NBT representation when sent in a packet. - NBTData map[string]interface{} + NBTData map[string]any // CanBePlacedOn is a list of block identifiers like 'minecraft:stone' which the item, if it is an item // that can be placed, can be placed on top of. CanBePlacedOn []string @@ -92,7 +92,7 @@ type ItemComponentEntry struct { // Name is the name of the item, which is a name like 'minecraft:stick'. Name string // Data is a map containing the components and properties of the item. - Data map[string]interface{} + Data map[string]any } // ItemComponents reads/writes an ItemComponentEntry x using IO r. diff --git a/minecraft/protocol/login/data.go b/minecraft/protocol/login/data.go index ff47346dc..847d5d662 100644 --- a/minecraft/protocol/login/data.go +++ b/minecraft/protocol/login/data.go @@ -317,7 +317,7 @@ func (data ClientData) Validate() error { if geomData, err := base64.StdEncoding.DecodeString(data.SkinGeometry); err != nil { return fmt.Errorf("SkinGeometry was not a valid base64 string: %v", err) } else if len(geomData) != 0 { - m := make(map[string]interface{}) + m := make(map[string]any) if err := json.Unmarshal(geomData, &m); err != nil { return fmt.Errorf("SkinGeometry base64 decoded was not a valid JSON string: %v", err) } @@ -326,7 +326,7 @@ func (data ClientData) Validate() error { if err != nil { return fmt.Errorf("SkinResourcePatch was not a valid base64 string: %v", err) } - m := make(map[string]interface{}) + m := make(map[string]any) if err := json.Unmarshal(b, &m); err != nil { return fmt.Errorf("SkinResourcePatch base64 decoded was not a valid JSON string: %v", err) } diff --git a/minecraft/protocol/login/request.go b/minecraft/protocol/login/request.go index 5295587de..f94757ee1 100644 --- a/minecraft/protocol/login/request.go +++ b/minecraft/protocol/login/request.go @@ -10,6 +10,7 @@ import ( "fmt" "gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2/jwt" + "strings" "time" ) @@ -76,7 +77,7 @@ func Parse(request []byte) (IdentityData, ClientData, AuthResult, error) { var identityClaims identityClaims var authenticated bool - t, iss := time.Now(), "NetEase" + t, iss := time.Now(), "Mojang" switch len(req.Chain) { case 1: @@ -97,7 +98,7 @@ func Parse(request []byte) (IdentityData, ClientData, AuthResult, error) { if err := c.Validate(jwt.Expected{Time: t}); err != nil { return iData, cData, res, fmt.Errorf("validate token 0: %w", err) } - authenticated = true//bytes.Equal(key.X.Bytes(), mojangKey.X.Bytes()) && bytes.Equal(key.Y.Bytes(), mojangKey.Y.Bytes()) + authenticated = bytes.Equal(key.X.Bytes(), mojangKey.X.Bytes()) && bytes.Equal(key.Y.Bytes(), mojangKey.Y.Bytes()) if err := parseFullClaim(req.Chain[1], key, &c); err != nil { return iData, cData, res, fmt.Errorf("parse token 1: %w", err) @@ -111,10 +112,10 @@ func Parse(request []byte) (IdentityData, ClientData, AuthResult, error) { if err := identityClaims.Validate(jwt.Expected{Time: t, Issuer: iss}); err != nil { return iData, cData, res, fmt.Errorf("validate token 2: %w", err) } - if authenticated != (identityClaims.ExtraData.XUID != "") { + /*if authenticated != (identityClaims.ExtraData.XUID != "") { return iData, cData, res, fmt.Errorf("identity data must have an XUID when logged into XBOX Live only") } - /*if authenticated != (identityClaims.ExtraData.TitleID != "") { + if authenticated != (identityClaims.ExtraData.TitleID != "") { return iData, cData, res, fmt.Errorf("identity data must have a title ID when logged into XBOX Live only") }*/ default: @@ -123,6 +124,12 @@ func Parse(request []byte) (IdentityData, ClientData, AuthResult, error) { if err := parseFullClaim(req.RawToken, key, &cData); err != nil { return iData, cData, res, fmt.Errorf("parse client data: %w", err) } + if strings.Count(cData.ServerAddress, ":") > 1 { + // IPv6: We can't net.ResolveUDPAddr this directly, because Mojang does not put [] around the IP. We'll have to + // do this manually: + ind := strings.LastIndex(cData.ServerAddress, ":") + cData.ServerAddress = "[" + cData.ServerAddress[:ind] + "]" + cData.ServerAddress[ind:] + } if err := cData.Validate(); err != nil { return iData, cData, res, fmt.Errorf("validate client data: %w", err) } @@ -149,12 +156,12 @@ func parseLoginRequest(requestData []byte) (*request, error) { // parseFullClaim parses and verifies a full claim using the ecdsa.PublicKey passed. The key passed is updated // if the claim holds an identityPublicKey field. // The value v passed is decoded into when reading the claims. -func parseFullClaim(claim string, key *ecdsa.PublicKey, v interface{}) error { +func parseFullClaim(claim string, key *ecdsa.PublicKey, v any) error { tok, err := jwt.ParseSigned(claim) if err != nil { return fmt.Errorf("error parsing signed token: %w", err) } - var m map[string]interface{} + var m map[string]any if err := tok.Claims(key, v, &m); err != nil { return fmt.Errorf("error verifying claims of token: %w", err) } @@ -169,7 +176,7 @@ func parseFullClaim(claim string, key *ecdsa.PublicKey, v interface{}) error { // parseAsKey parses the base64 encoded ecdsa.PublicKey held in k as a public key and sets it to the variable // pub passed. -func parseAsKey(k interface{}, pub *ecdsa.PublicKey) error { +func parseAsKey(k any, pub *ecdsa.PublicKey) error { kStr, _ := k.(string) if err := ParsePublicKey(kStr, pub); err != nil { return fmt.Errorf("error parsing public key: %w", err) @@ -198,7 +205,7 @@ func Encode(loginChain string, data ClientData, key *ecdsa.PrivateKey) []byte { } signer, _ := jose.NewSigner(jose.SigningKey{Key: key, Algorithm: jose.ES384}, &jose.SignerOptions{ - ExtraHeaders: map[jose.HeaderKey]interface{}{"x5u": keyData}, + ExtraHeaders: map[jose.HeaderKey]any{"x5u": keyData}, }) firstJWT, _ := jwt.Signed(signer).Claims(identityPublicKeyClaims{ Claims: claims, @@ -241,7 +248,7 @@ func EncodeOffline(identityData IdentityData, data ClientData, key *ecdsa.Privat } signer, _ := jose.NewSigner(jose.SigningKey{Key: key, Algorithm: jose.ES384}, &jose.SignerOptions{ - ExtraHeaders: map[jose.HeaderKey]interface{}{"x5u": keyData}, + ExtraHeaders: map[jose.HeaderKey]any{"x5u": keyData}, }) firstJWT, _ := jwt.Signed(signer).Claims(identityClaims{ Claims: claims, diff --git a/minecraft/protocol/packet/actor_event.go b/minecraft/protocol/packet/actor_event.go index 08aa53152..43196c2f7 100644 --- a/minecraft/protocol/packet/actor_event.go +++ b/minecraft/protocol/packet/actor_event.go @@ -48,6 +48,8 @@ const ( const ( ActorEventFeed = iota + 57 + _ + _ ActorEventBabyEat ActorEventInstantDeath ActorEventNotifyTrade @@ -65,6 +67,7 @@ const ( ActorEventFinishedChargingCrossbow ActorEventLandedOnGround ActorEventActorGrowUp + ActorEventVibrationDetected ) // ActorEvent is sent by the server when a particular event happens that has to do with an entity. Some of diff --git a/minecraft/protocol/packet/add_actor.go b/minecraft/protocol/packet/add_actor.go index 9c300d662..76436f20c 100644 --- a/minecraft/protocol/packet/add_actor.go +++ b/minecraft/protocol/packet/add_actor.go @@ -38,7 +38,7 @@ type AddActor struct { // EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in // particular the way the entity looks. Flags include ones such as 'on fire' and 'sprinting'. // The metadata values are indexed by their property key. - EntityMetadata map[uint32]interface{} + EntityMetadata map[uint32]any // EntityLinks is a list of entity links that are currently active on the entity. These links alter the // way the entity shows up when first spawned in terms of it shown as riding an entity. Setting these // links is important for new viewers to see the entity is riding another entity. diff --git a/minecraft/protocol/packet/add_item_actor.go b/minecraft/protocol/packet/add_item_actor.go index 66844d8e0..f19bf6f74 100644 --- a/minecraft/protocol/packet/add_item_actor.go +++ b/minecraft/protocol/packet/add_item_actor.go @@ -27,7 +27,7 @@ type AddItemActor struct { // EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in // particular the way the entity looks. Flags include ones such as 'on fire' and 'sprinting'. // The metadata values are indexed by their property key. - EntityMetadata map[uint32]interface{} + EntityMetadata map[uint32]any // FromFishing specifies if the item was obtained by fishing it up using a fishing rod. It is not clear // why the client needs to know this. FromFishing bool diff --git a/minecraft/protocol/packet/add_player.go b/minecraft/protocol/packet/add_player.go index 486f6552b..19d5f1e9d 100644 --- a/minecraft/protocol/packet/add_player.go +++ b/minecraft/protocol/packet/add_player.go @@ -45,11 +45,13 @@ type AddPlayer struct { // itself shows up. Needless to say that this field is rather pointless, as additional packets still must // be sent for armour to show up. HeldItem protocol.ItemInstance + // GameType is the game type of the player. If set to GameTypeSpectator, the player will not be shown to viewers. + GameType int32 // EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in // particular the way the player looks. Flags include ones such as 'on fire' and 'sprinting'. // The metadata values are indexed by their property key. - EntityMetadata map[uint32]interface{} - // Flags is a set of flags that specify certain properties of the player, such as whether or not it can + EntityMetadata map[uint32]any + // Flags is a set of flags that specify certain properties of the player, such as whether it can // fly and/or move through blocks. Flags uint32 // CommandPermissionLevel is a set of permissions that specify what commands a player is allowed to execute. @@ -95,6 +97,7 @@ func (pk *AddPlayer) Marshal(w *protocol.Writer) { w.Float32(&pk.Yaw) w.Float32(&pk.HeadYaw) w.ItemInstance(&pk.HeldItem) + w.Varint32(&pk.GameType) w.EntityMetadata(&pk.EntityMetadata) w.Varuint32(&pk.Flags) w.Varuint32(&pk.CommandPermissionLevel) @@ -120,6 +123,7 @@ func (pk *AddPlayer) Unmarshal(r *protocol.Reader) { r.Float32(&pk.Yaw) r.Float32(&pk.HeadYaw) r.ItemInstance(&pk.HeldItem) + r.Varint32(&pk.GameType) r.EntityMetadata(&pk.EntityMetadata) r.Varuint32(&pk.Flags) r.Varuint32(&pk.CommandPermissionLevel) diff --git a/minecraft/protocol/packet/add_volume_entity.go b/minecraft/protocol/packet/add_volume_entity.go index 67e57233c..934311367 100644 --- a/minecraft/protocol/packet/add_volume_entity.go +++ b/minecraft/protocol/packet/add_volume_entity.go @@ -12,12 +12,17 @@ type AddVolumeEntity struct { EntityRuntimeID uint64 // EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in // particular the way the volume functions or looks. - EntityMetadata map[string]interface{} + EntityMetadata map[string]any // EncodingIdentifier is the unique identifier for the volume. It must be of the form 'namespace:name', where // namespace cannot be 'minecraft'. EncodingIdentifier string // InstanceIdentifier is the identifier of a fog definition. InstanceIdentifier string + // Bounds represent the volume's bounds. The first value is the minimum bounds, and the second value is the + // maximum bounds. + Bounds [2]protocol.BlockPos + // Dimension is the dimension in which the volume exists. + Dimension int32 // EngineVersion is the engine version the entity is using, for example, '1.17.0'. EngineVersion string } @@ -33,6 +38,9 @@ func (pk *AddVolumeEntity) Marshal(w *protocol.Writer) { w.NBT(&pk.EntityMetadata, nbt.NetworkLittleEndian) w.String(&pk.EncodingIdentifier) w.String(&pk.InstanceIdentifier) + w.UBlockPos(&pk.Bounds[0]) + w.UBlockPos(&pk.Bounds[1]) + w.Varint32(&pk.Dimension) w.String(&pk.EngineVersion) } @@ -42,5 +50,8 @@ func (pk *AddVolumeEntity) Unmarshal(r *protocol.Reader) { r.NBT(&pk.EntityMetadata, nbt.NetworkLittleEndian) r.String(&pk.EncodingIdentifier) r.String(&pk.InstanceIdentifier) + r.UBlockPos(&pk.Bounds[0]) + r.UBlockPos(&pk.Bounds[1]) + r.Varint32(&pk.Dimension) r.String(&pk.EngineVersion) } diff --git a/minecraft/protocol/packet/adventure_settings.go b/minecraft/protocol/packet/adventure_settings.go index f76de2af0..1b2bba5ce 100644 --- a/minecraft/protocol/packet/adventure_settings.go +++ b/minecraft/protocol/packet/adventure_settings.go @@ -34,9 +34,9 @@ const ( ActionPermissionAttackPlayers ActionPermissionAttackMobs ActionPermissionOperator - ActionPermissionUnknown ActionPermissionTeleport ActionPermissionBuild + ActionPermissionDefault ) const ( diff --git a/minecraft/protocol/packet/agent_action.go b/minecraft/protocol/packet/agent_action.go new file mode 100644 index 000000000..b41750bfc --- /dev/null +++ b/minecraft/protocol/packet/agent_action.go @@ -0,0 +1,56 @@ +package packet + +import ( + "phoenixbuilder/minecraft/protocol" +) + +const ( + AgentActionTypeAttack = iota + 1 + AgentActionTypeCollect + AgentActionTypeDestroy + AgentActionTypeDetectRedstone + AgentActionTypeDetectObstacle + AgentActionTypeDrop + AgentActionTypeDropAll + AgentActionTypeInspect + AgentActionTypeInspectData + AgentActionTypeInspectItemCount + AgentActionTypeInspectItemDetail + AgentActionTypeInspectItemSpace + AgentActionTypeInteract + AgentActionTypeMove + AgentActionTypePlaceBlock + AgentActionTypeTill + AgentActionTypeTransferItemTo + AgentActionTypeTurn +) + +// AgentAction is an Education Edition packet sent from the server to the client to return a response to a +// previously requested action. +type AgentAction struct { + // Identifier is a JSON identifier referenced in the initial action. + Identifier string + // Action represents the action type that was requested. It is one of the constants defined above. + Action int32 + // Response is a JSON string containing the response to the action. + Response []byte +} + +// ID ... +func (*AgentAction) ID() uint32 { + return IDAgentAction +} + +// Marshal ... +func (pk *AgentAction) Marshal(w *protocol.Writer) { + w.String(&pk.Identifier) + w.Varint32(&pk.Action) + w.ByteSlice(&pk.Response) +} + +// Unmarshal ... +func (pk *AgentAction) Unmarshal(r *protocol.Reader) { + r.String(&pk.Identifier) + r.Varint32(&pk.Action) + r.ByteSlice(&pk.Response) +} diff --git a/minecraft/protocol/packet/animate_entity.go b/minecraft/protocol/packet/animate_entity.go index 0e03ae28c..5a685654c 100644 --- a/minecraft/protocol/packet/animate_entity.go +++ b/minecraft/protocol/packet/animate_entity.go @@ -51,7 +51,6 @@ func (pk *AnimateEntity) Marshal(w *protocol.Writer) { // Unmarshal ... func (pk *AnimateEntity) Unmarshal(r *protocol.Reader) { - return r.String(&pk.Animation) r.String(&pk.NextState) r.String(&pk.StopCondition) diff --git a/minecraft/protocol/packet/block_actor_data.go b/minecraft/protocol/packet/block_actor_data.go index 567f8a842..a751c6ad0 100644 --- a/minecraft/protocol/packet/block_actor_data.go +++ b/minecraft/protocol/packet/block_actor_data.go @@ -14,7 +14,7 @@ type BlockActorData struct { // NBTData is the new data of the block that will be encoded to NBT and applied client-side, so that the // client can see the block update. The NBTData should contain all properties of the block, not just // properties that were changed. - NBTData map[string]interface{} + NBTData map[string]any } // ID ... @@ -30,7 +30,7 @@ func (pk *BlockActorData) Marshal(w *protocol.Writer) { // Unmarshal ... func (pk *BlockActorData) Unmarshal(r *protocol.Reader) { - pk.NBTData = make(map[string]interface{}) + pk.NBTData = make(map[string]any) r.UBlockPos(&pk.Position) r.NBT(&pk.NBTData, nbt.NetworkLittleEndian) } diff --git a/minecraft/protocol/packet/change_mob_property.go b/minecraft/protocol/packet/change_mob_property.go new file mode 100644 index 000000000..60b2759e4 --- /dev/null +++ b/minecraft/protocol/packet/change_mob_property.go @@ -0,0 +1,46 @@ +package packet + +import ( + "phoenixbuilder/minecraft/protocol" +) + +// ChangeMobProperty is a packet sent from the server to the client to change one of the properties of a mob client-side. +type ChangeMobProperty struct { + // EntityUniqueID is the unique ID of the entity whose property is being changed. + EntityUniqueID uint64 + // Property is the name of the property being updated. + Property string + // BoolValue is set if the property value is a bool type. If the type is not a bool, this field is ignored. + BoolValue bool + // StringValue is set if the property value is a string type. If the type is not a string, this field is ignored. + StringValue string + // IntValue is set if the property value is an int type. If the type is not an int, this field is ignored. + IntValue int32 + // FloatValue is set if the property value is a float type. If the type is not a float, this field is ignored. + FloatValue float32 +} + +// ID ... +func (*ChangeMobProperty) ID() uint32 { + return IDChangeMobProperty +} + +// Marshal ... +func (pk *ChangeMobProperty) Marshal(w *protocol.Writer) { + w.Uint64(&pk.EntityUniqueID) + w.String(&pk.Property) + w.Bool(&pk.BoolValue) + w.String(&pk.StringValue) + w.Varint32(&pk.IntValue) + w.Float32(&pk.FloatValue) +} + +// Unmarshal ... +func (pk *ChangeMobProperty) Unmarshal(r *protocol.Reader) { + r.Uint64(&pk.EntityUniqueID) + r.String(&pk.Property) + r.Bool(&pk.BoolValue) + r.String(&pk.StringValue) + r.Varint32(&pk.IntValue) + r.Float32(&pk.FloatValue) +} diff --git a/minecraft/protocol/packet/command_request.go b/minecraft/protocol/packet/command_request.go index 8bfb9922c..80df584d6 100644 --- a/minecraft/protocol/packet/command_request.go +++ b/minecraft/protocol/packet/command_request.go @@ -17,6 +17,7 @@ type CommandRequest struct { // Internal specifies if the command request internal. Setting it to false seems to work and the usage of // this field is not known. Internal bool + // Unknown NetEase specified field UnLimited bool } diff --git a/minecraft/protocol/packet/correct_player_move_prediction.go b/minecraft/protocol/packet/correct_player_move_prediction.go index 32832d62d..325d6cfda 100644 --- a/minecraft/protocol/packet/correct_player_move_prediction.go +++ b/minecraft/protocol/packet/correct_player_move_prediction.go @@ -9,7 +9,7 @@ import ( // is set to AuthoritativeMovementModeServerWithRewind. The packet is used to correct movement at a specific // point in time. type CorrectPlayerMovePrediction struct { - // Position is the position that the player is supposed to be at at the tick written in the field below. + // Position is the position that the player is supposed to be at the tick written in the field below. // The client will change its current position based on movement after that tick starting from the // Position. Position mgl32.Vec3 diff --git a/minecraft/protocol/packet/dimension_data.go b/minecraft/protocol/packet/dimension_data.go new file mode 100644 index 000000000..4a49bbda4 --- /dev/null +++ b/minecraft/protocol/packet/dimension_data.go @@ -0,0 +1,38 @@ +package packet + +import ( + "phoenixbuilder/minecraft/protocol" +) + +// DimensionData is a packet sent from the server to the client containing information about data-driven dimensions +// that the server may have registered. This packet does not seem to be sent by default, rather only being sent when +// any data-driven dimensions are registered. +type DimensionData struct { + // Definitions contain a list of data-driven dimension definitions registered on the server. + Definitions []protocol.DimensionDefinition +} + +// ID ... +func (*DimensionData) ID() uint32 { + return IDDimensionData +} + +// Marshal ... +func (pk *DimensionData) Marshal(w *protocol.Writer) { + definitionsLen := uint32(len(pk.Definitions)) + w.Varuint32(&definitionsLen) + for _, definition := range pk.Definitions { + protocol.DimensionDef(w, &definition) + } +} + +// Unmarshal ... +func (pk *DimensionData) Unmarshal(r *protocol.Reader) { + var definitionsLen uint32 + r.Varuint32(&definitionsLen) + + pk.Definitions = make([]protocol.DimensionDefinition, definitionsLen) + for i := uint32(0); i < definitionsLen; i++ { + protocol.DimensionDef(r, &pk.Definitions[i]) + } +} diff --git a/minecraft/protocol/packet/id.go b/minecraft/protocol/packet/id.go index d04eca4d3..8e4accba0 100644 --- a/minecraft/protocol/packet/id.go +++ b/minecraft/protocol/packet/id.go @@ -179,5 +179,8 @@ const ( IDClientStartItemCooldown IDScriptMessage IDCodeBuilderSource - IDPyRpc = 0xC8 + IDTickingAreasLoadStatus + IDDimensionData + IDAgentAction + IDChangeMobProperty ) diff --git a/minecraft/protocol/packet/level_event.go b/minecraft/protocol/packet/level_event.go index 21ce9bb1c..9a17cdf4c 100644 --- a/minecraft/protocol/packet/level_event.go +++ b/minecraft/protocol/packet/level_event.go @@ -83,6 +83,8 @@ const ( LevelEventParticleTurtleEgg = 2034 LevelEventParticleSculkShriek = 2035 LevelEventSculkCatalystBloom = 2036 + LevelEventSculkCharge = 2037 + LevelEventSculkChargePop = 2038 LevelEventStartRaining = 3001 LevelEventStartThunderstorm = 3002 LevelEventStopRaining = 3003 diff --git a/minecraft/protocol/packet/level_sound_event.go b/minecraft/protocol/packet/level_sound_event.go index fc6b52d09..d0e0ba818 100644 --- a/minecraft/protocol/packet/level_sound_event.go +++ b/minecraft/protocol/packet/level_sound_event.go @@ -382,6 +382,54 @@ const ( SoundEventTongue SoundEventCrackIronGolem SoundEventRepairIronGolem + SoundEventListening + SoundEventHeartbeat + SoundEventHornBreak + SoundEventSculkPlace + SoundEventSculkSpread + SoundEventSculkCharge + SoundEventSculkSensorPlace + SoundEventSculkShriekerPlace + SoundEventGoatCall0 + SoundEventGoatCall1 + SoundEventGoatCall2 + SoundEventGoatCall3 + SoundEventGoatCall4 + SoundEventGoatCall5 + SoundEventGoatCall6 + SoundEventGoatCall7 + SoundEventGoatCall8 + SoundEventGoatCall9 + SoundEventGoatHarmony0 + SoundEventGoatHarmony1 + SoundEventGoatHarmony2 + SoundEventGoatHarmony3 + SoundEventGoatHarmony4 + SoundEventGoatHarmony5 + SoundEventGoatHarmony6 + SoundEventGoatHarmony7 + SoundEventGoatHarmony8 + SoundEventGoatHarmony9 + SoundEventGoatMelody0 + SoundEventGoatMelody1 + SoundEventGoatMelody2 + SoundEventGoatMelody3 + SoundEventGoatMelody4 + SoundEventGoatMelody5 + SoundEventGoatMelody6 + SoundEventGoatMelody7 + SoundEventGoatMelody8 + SoundEventGoatMelody9 + SoundEventGoatBass0 + SoundEventGoatBass1 + SoundEventGoatBass2 + SoundEventGoatBass3 + SoundEventGoatBass4 + SoundEventGoatBass5 + SoundEventGoatBass6 + SoundEventGoatBass7 + SoundEventGoatBass8 + SoundEventGoatBass9 SoundEventUndefined ) diff --git a/minecraft/protocol/packet/npc_dialogue.go b/minecraft/protocol/packet/npc_dialogue.go index 29903ad24..036a16001 100644 --- a/minecraft/protocol/packet/npc_dialogue.go +++ b/minecraft/protocol/packet/npc_dialogue.go @@ -9,8 +9,8 @@ const ( // NPCDialogue is a packet that allows the client to display dialog boxes for interacting with NPCs. type NPCDialogue struct { - // ActorUniqueID is the ID of the NPC being requested. - ActorUniqueID uint64 + // EntityUniqueID is the unique ID of the NPC being requested. + EntityUniqueID uint64 // ActionType is the type of action for the packet. ActionType int32 // Dialogue is the text that the client should see. @@ -31,7 +31,7 @@ func (*NPCDialogue) ID() uint32 { // Marshal ... func (pk *NPCDialogue) Marshal(w *protocol.Writer) { - w.Uint64(&pk.ActorUniqueID) + w.Uint64(&pk.EntityUniqueID) w.Varint32(&pk.ActionType) w.String(&pk.Dialogue) w.String(&pk.SceneName) @@ -41,7 +41,7 @@ func (pk *NPCDialogue) Marshal(w *protocol.Writer) { // Unmarshal ... func (pk *NPCDialogue) Unmarshal(r *protocol.Reader) { - r.Uint64(&pk.ActorUniqueID) + r.Uint64(&pk.EntityUniqueID) r.Varint32(&pk.ActionType) r.String(&pk.Dialogue) r.String(&pk.SceneName) diff --git a/minecraft/protocol/packet/pool.go b/minecraft/protocol/packet/pool.go index b05d9a6e8..e91c0fc3e 100644 --- a/minecraft/protocol/packet/pool.go +++ b/minecraft/protocol/packet/pool.go @@ -202,7 +202,10 @@ func init() { IDClientStartItemCooldown: func() Packet { return &ClientStartItemCooldown{} }, IDScriptMessage: func() Packet { return &ScriptMessage{} }, IDCodeBuilderSource: func() Packet { return &CodeBuilderSource{} }, - IDPyRpc: func() Packet { return &PyRpc{} }, + IDTickingAreasLoadStatus: func() Packet { return &TickingAreasLoadStatus{} }, + IDDimensionData: func() Packet { return &DimensionData{} }, + IDAgentAction: func() Packet { return &AgentAction{} }, + IDChangeMobProperty: func() Packet { return &ChangeMobProperty{} }, } for id, pk := range packets { Register(id, pk) diff --git a/minecraft/protocol/packet/py_rpc.go b/minecraft/protocol/packet/py_rpc.go deleted file mode 100644 index b8ebc807b..000000000 --- a/minecraft/protocol/packet/py_rpc.go +++ /dev/null @@ -1,37 +0,0 @@ -package packet - -import ( - "phoenixbuilder/minecraft/protocol" -) - -// Netease PyRpc - -type PyRpc struct { - Content []byte -} - -// ID ... -func (*PyRpc) ID() uint32 { - return IDPyRpc -} - -// Marshal ... -func (pk *PyRpc) Marshal(w *protocol.Writer) { - w.ByteSlice(&pk.Content) - w.Bytes(&[]byte{0xae,0x23,0xdb,0x05}) - //fmt.Printf("%d\n",len(pk.Content)) - //fmt.Printf("%X\n",buf.Bytes()) - //_ = protocol.WriteByteSlice(buf, pk.Content) - //_ = protocol.WriteVaruint32(buf, pk.DisallowBatching) - //buf.Write([]byte{0xae,0x23,0xdb,0x05}) - //fmt.Printf("%X\n\n",buf.Bytes()) - //var outuint32 uint32 - //protocol.Varuint32(bytes.NewBuffer([]byte{0xae,0x23,0xdb,0x05}),&outuint32) - //fmt.Printf("%d\n",outuint32) - -} - -// Unmarshal ... -func (pk *PyRpc) Unmarshal(r *protocol.Reader) { - r.ByteSlice(&pk.Content) -} diff --git a/minecraft/protocol/packet/remove_volume_entity.go b/minecraft/protocol/packet/remove_volume_entity.go index 9b7039561..cf052fa21 100644 --- a/minecraft/protocol/packet/remove_volume_entity.go +++ b/minecraft/protocol/packet/remove_volume_entity.go @@ -8,6 +8,8 @@ import ( type RemoveVolumeEntity struct { // EntityRuntimeID ... EntityRuntimeID uint64 + // Dimension ... + Dimension int32 } // ID ... @@ -18,9 +20,11 @@ func (*RemoveVolumeEntity) ID() uint32 { // Marshal ... func (pk *RemoveVolumeEntity) Marshal(w *protocol.Writer) { w.Uint64(&pk.EntityRuntimeID) + w.Varint32(&pk.Dimension) } // Unmarshal ... func (pk *RemoveVolumeEntity) Unmarshal(r *protocol.Reader) { r.Uint64(&pk.EntityRuntimeID) + r.Varint32(&pk.Dimension) } diff --git a/minecraft/protocol/packet/set_actor_data.go b/minecraft/protocol/packet/set_actor_data.go index 8fcfedc1e..e084e6f03 100644 --- a/minecraft/protocol/packet/set_actor_data.go +++ b/minecraft/protocol/packet/set_actor_data.go @@ -13,7 +13,7 @@ type SetActorData struct { // EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in // particular the way the entity looks. Flags include ones such as 'on fire' and 'sprinting'. // The metadata values are indexed by their property key. - EntityMetadata map[uint32]interface{} + EntityMetadata map[uint32]any // Tick is the server tick at which the packet was sent. It is used in relation to CorrectPlayerMovePrediction. Tick uint64 } diff --git a/minecraft/protocol/packet/set_player_game_type.go b/minecraft/protocol/packet/set_player_game_type.go index 1db0fc8ce..7ed19e742 100644 --- a/minecraft/protocol/packet/set_player_game_type.go +++ b/minecraft/protocol/packet/set_player_game_type.go @@ -10,6 +10,8 @@ const ( GameTypeAdventure GameTypeSurvivalSpectator GameTypeCreativeSpectator + GameTypeDefault + GameTypeSpectator ) // SetPlayerGameType is sent by the server to update the game type, which is otherwise known as the game mode, diff --git a/minecraft/protocol/packet/spawn_particle_effect.go b/minecraft/protocol/packet/spawn_particle_effect.go index dbbcc7d90..a1820c98d 100644 --- a/minecraft/protocol/packet/spawn_particle_effect.go +++ b/minecraft/protocol/packet/spawn_particle_effect.go @@ -23,6 +23,9 @@ type SpawnParticleEffect struct { // ParticleName is the name of the particle that should be shown. This name may point to a particle effect // that is built-in, or to one implemented by behaviour packs. ParticleName string + // MoLangVariables is an encoded JSON map of MoLang variables that may be applicable to the particle spawn. This can + // just be left empty in most cases. + MoLangVariables []byte } // ID ... @@ -36,6 +39,12 @@ func (pk *SpawnParticleEffect) Marshal(w *protocol.Writer) { w.Varint64(&pk.EntityUniqueID) w.Vec3(&pk.Position) w.String(&pk.ParticleName) + + exists := len(pk.MoLangVariables) > 0 + w.Bool(&exists) + if exists { + w.ByteSlice(&pk.MoLangVariables) + } } // Unmarshal ... @@ -44,4 +53,11 @@ func (pk *SpawnParticleEffect) Unmarshal(r *protocol.Reader) { r.Varint64(&pk.EntityUniqueID) r.Vec3(&pk.Position) r.String(&pk.ParticleName) + r.ByteSlice(&pk.MoLangVariables) + + var exists bool + r.Bool(&exists) + if exists { + r.ByteSlice(&pk.MoLangVariables) + } } diff --git a/minecraft/protocol/packet/start_game.go b/minecraft/protocol/packet/start_game.go index 5386a84d1..9b51b0066 100644 --- a/minecraft/protocol/packet/start_game.go +++ b/minecraft/protocol/packet/start_game.go @@ -37,7 +37,7 @@ type StartGame struct { Yaw float32 // WorldSeed is the seed used to generate the world. Unlike in PC edition, the seed is a 32bit integer // here. - WorldSeed int32 + WorldSeed uint64 // SpawnBiomeType specifies if the biome that the player spawns in is user defined (through behaviour // packs) or builtin. See the constants above. SpawnBiomeType int16 @@ -212,7 +212,7 @@ func (pk *StartGame) Marshal(w *protocol.Writer) { w.Vec3(&pk.PlayerPosition) w.Float32(&pk.Pitch) w.Float32(&pk.Yaw) - w.Varint32(&pk.WorldSeed) + w.Uint64(&pk.WorldSeed) w.Int16(&pk.SpawnBiomeType) w.String(&pk.UserDefinedBiomeName) w.Varint32(&pk.Dimension) @@ -297,7 +297,7 @@ func (pk *StartGame) Unmarshal(r *protocol.Reader) { r.Vec3(&pk.PlayerPosition) r.Float32(&pk.Pitch) r.Float32(&pk.Yaw) - r.Varint32(&pk.WorldSeed) + r.Uint64(&pk.WorldSeed) r.Int16(&pk.SpawnBiomeType) r.String(&pk.UserDefinedBiomeName) r.Varint32(&pk.Dimension) diff --git a/minecraft/protocol/packet/structure_template_data_response.go b/minecraft/protocol/packet/structure_template_data_response.go index 2c714a7e2..be4dc35db 100644 --- a/minecraft/protocol/packet/structure_template_data_response.go +++ b/minecraft/protocol/packet/structure_template_data_response.go @@ -23,7 +23,7 @@ type StructureTemplateDataResponse struct { // the StructureTemplateDataRequest packet and is one of the constants above. ResponseType byte // StructureTemplate holds the data of the structure template. - StructureTemplate map[string]interface{} + StructureTemplate map[string]any } // ID ... diff --git a/minecraft/protocol/packet/sub_chunk.go b/minecraft/protocol/packet/sub_chunk.go index 9e76d0548..1259f4c6e 100644 --- a/minecraft/protocol/packet/sub_chunk.go +++ b/minecraft/protocol/packet/sub_chunk.go @@ -4,40 +4,16 @@ import ( "phoenixbuilder/minecraft/protocol" ) -const ( - SubChunkRequestResultUndefined int32 = iota - SubChunkRequestResultSuccess - SubChunkRequestResultChunkNotFound - SubChunkRequestResultInvalidDimension - SubChunkRequestResultPlayerNotFound - SubChunkRequestResultIndexOutOfBounds -) - -const ( - HeightMapDataTypeNone byte = iota - HeightMapDataTypeHasData - HeightMapDataTypeTooHigh - HeightMapDataTypeTooLow -) - // SubChunk sends data about multiple sub-chunks around a center point. type SubChunk struct { - // Dimension is the dimension of the sub chunk. - Dimension int32 - // SubChunkX, SubChunkY, and SubChunkZ help identify the sub chunk. - SubChunkX, SubChunkY, SubChunkZ int32 - // Data is the actual sub chunk data, such as the blocks. - Data []byte - // RequestResult is one of the values above. - RequestResult int32 - // HeightMapType is one of the values above. - HeightMapType byte - // HeightMapData is the data for the height map. - HeightMapData []byte - // CacheEnabled is whether the sub chunk caching is enabled or not. + // CacheEnabled is whether the sub-chunk caching is enabled or not. CacheEnabled bool - // BlobHash is the hash of the blob. - BlobHash uint64 + // Dimension is the dimension the sub-chunks are in. + Dimension int32 + // Position is an absolute sub-chunk center point that every SubChunkRequest uses as a reference. + Position protocol.SubChunkPos + // SubChunkEntries contains sub-chunk entries relative to the center point. + SubChunkEntries []protocol.SubChunkEntry } // ID ... @@ -47,45 +23,69 @@ func (*SubChunk) ID() uint32 { // Marshal ... func (pk *SubChunk) Marshal(w *protocol.Writer) { + w.Bool(&pk.CacheEnabled) w.Varint32(&pk.Dimension) - w.Varint32(&pk.SubChunkX) - w.Varint32(&pk.SubChunkY) - w.Varint32(&pk.SubChunkZ) - w.ByteSlice(&pk.Data) - w.Varint32(&pk.RequestResult) - - w.Uint8(&pk.HeightMapType) - if pk.HeightMapType == HeightMapDataTypeHasData { - for i := 0; i < 256; i++ { - w.Uint8(&pk.HeightMapData[i]) + w.SubChunkPos(&pk.Position) + + count := uint32(len(pk.SubChunkEntries)) + w.Uint32(&count) + for _, entry := range pk.SubChunkEntries { + w.Int8(&entry.Offset[0]) + w.Int8(&entry.Offset[1]) + w.Int8(&entry.Offset[2]) + + w.Uint8(&entry.Result) + if !pk.CacheEnabled || entry.Result != protocol.SubChunkResultSuccessAllAir { + w.ByteSlice(&entry.RawPayload) } - } - w.Bool(&pk.CacheEnabled) - if pk.CacheEnabled { - w.Uint64(&pk.BlobHash) + w.Uint8(&entry.HeightMapType) + if entry.HeightMapType == protocol.HeightMapDataHasData { + for i := 0; i < 256; i++ { + w.Int8(&entry.HeightMapData[i]) + } + } + + if pk.CacheEnabled { + w.Uint64(&entry.BlobHash) + } } } // Unmarshal ... func (pk *SubChunk) Unmarshal(r *protocol.Reader) { + r.Bool(&pk.CacheEnabled) r.Varint32(&pk.Dimension) - r.Varint32(&pk.SubChunkX) - r.Varint32(&pk.SubChunkY) - r.Varint32(&pk.SubChunkZ) - r.ByteSlice(&pk.Data) - r.Varint32(&pk.RequestResult) - - r.Uint8(&pk.HeightMapType) - if pk.HeightMapType == HeightMapDataTypeHasData { - pk.HeightMapData = make([]uint8, 256) - for i := 0; i < 256; i++ { - r.Uint8(&pk.HeightMapData[i]) + r.SubChunkPos(&pk.Position) + + var count uint32 + r.Uint32(&count) + + pk.SubChunkEntries = make([]protocol.SubChunkEntry, count) + for i := uint32(0); i < count; i++ { + var entry protocol.SubChunkEntry + + r.Int8(&entry.Offset[0]) + r.Int8(&entry.Offset[1]) + r.Int8(&entry.Offset[2]) + + r.Uint8(&entry.Result) + if !pk.CacheEnabled || entry.Result != protocol.SubChunkResultSuccessAllAir { + r.ByteSlice(&entry.RawPayload) } - } - r.Bool(&pk.CacheEnabled) - if pk.CacheEnabled { - r.Uint64(&pk.BlobHash) + r.Uint8(&entry.HeightMapType) + if entry.HeightMapType == protocol.HeightMapDataHasData { + entry.HeightMapData = make([]int8, 256) + for i := 0; i < 256; i++ { + r.Int8(&entry.HeightMapData[i]) + } + } + + if pk.CacheEnabled { + r.Uint64(&entry.BlobHash) + } + + pk.SubChunkEntries[i] = entry } } diff --git a/minecraft/protocol/packet/sub_chunk_request.go b/minecraft/protocol/packet/sub_chunk_request.go index 39404dcea..01756dfa2 100644 --- a/minecraft/protocol/packet/sub_chunk_request.go +++ b/minecraft/protocol/packet/sub_chunk_request.go @@ -25,13 +25,13 @@ func (pk *SubChunkRequest) Marshal(w *protocol.Writer) { w.Varint32(&pk.Dimension) w.SubChunkPos(&pk.Position) - /*count := uint32(len(pk.Offsets)) + count := uint32(len(pk.Offsets)) w.Uint32(&count) for _, offset := range pk.Offsets { w.Int8(&offset[0]) w.Int8(&offset[1]) w.Int8(&offset[2]) - }*/ + } } // Unmarshal ... diff --git a/minecraft/protocol/packet/sync_actor_property.go b/minecraft/protocol/packet/sync_actor_property.go index 1337098be..990cd5209 100644 --- a/minecraft/protocol/packet/sync_actor_property.go +++ b/minecraft/protocol/packet/sync_actor_property.go @@ -8,7 +8,7 @@ import ( // SyncActorProperty is an alternative to synced actor data. type SyncActorProperty struct { // PropertyData ... - PropertyData map[string]interface{} + PropertyData map[string]any } // ID ... diff --git a/minecraft/protocol/packet/ticking_areas_load_status.go b/minecraft/protocol/packet/ticking_areas_load_status.go new file mode 100644 index 000000000..95214bdc9 --- /dev/null +++ b/minecraft/protocol/packet/ticking_areas_load_status.go @@ -0,0 +1,24 @@ +package packet + +import "phoenixbuilder/minecraft/protocol" + +// TickingAreasLoadStatus is sent by the server to the client to notify the client of a ticking area's loading status. +type TickingAreasLoadStatus struct { + // Preload is true if the server is waiting for the area's preload. + Preload bool +} + +// ID ... +func (*TickingAreasLoadStatus) ID() uint32 { + return IDTickingAreasLoadStatus +} + +// Marshal ... +func (pk *TickingAreasLoadStatus) Marshal(w *protocol.Writer) { + w.Bool(&pk.Preload) +} + +// Unmarshal ... +func (pk *TickingAreasLoadStatus) Unmarshal(r *protocol.Reader) { + r.Bool(&pk.Preload) +} diff --git a/minecraft/protocol/packet/update_attributes.go b/minecraft/protocol/packet/update_attributes.go index 703626a2a..0b3987876 100644 --- a/minecraft/protocol/packet/update_attributes.go +++ b/minecraft/protocol/packet/update_attributes.go @@ -32,8 +32,6 @@ func (pk *UpdateAttributes) Marshal(w *protocol.Writer) { // Unmarshal ... func (pk *UpdateAttributes) Unmarshal(r *protocol.Reader) { - // Simple bad patch: no unmarshal - return r.Varuint64(&pk.EntityRuntimeID) protocol.Attributes(r, &pk.Attributes) r.Varuint64(&pk.Tick) diff --git a/minecraft/protocol/packet/update_block.go b/minecraft/protocol/packet/update_block.go index fa9569356..eb45bcbb7 100644 --- a/minecraft/protocol/packet/update_block.go +++ b/minecraft/protocol/packet/update_block.go @@ -5,10 +5,10 @@ import ( ) const ( - BlockUpdateNeighbours = 1 << iota //1 - BlockUpdateNetwork //2 - BlockUpdateNoGraphics //4 - BlockUpdatePriority //8 + BlockUpdateNeighbours = 1 << iota + BlockUpdateNetwork + BlockUpdateNoGraphics + BlockUpdatePriority ) // UpdateBlock is sent by the server to update a block client-side, without resending the entire chunk that diff --git a/minecraft/protocol/reader.go b/minecraft/protocol/reader.go index 671aa4adc..23bb16787 100644 --- a/minecraft/protocol/reader.go +++ b/minecraft/protocol/reader.go @@ -9,7 +9,6 @@ import ( "phoenixbuilder/minecraft/nbt" "image/color" "io" - "io/ioutil" "math" "unsafe" ) @@ -170,21 +169,21 @@ func (r *Reader) VarRGBA(x *color.RGBA) { // Bytes reads the leftover bytes into a byte slice. func (r *Reader) Bytes(p *[]byte) { var err error - *p, err = ioutil.ReadAll(r.r) + *p, err = io.ReadAll(r.r) if err != nil { r.panic(err) } } // NBT reads a compound tag into a map from the underlying buffer. -func (r *Reader) NBT(m *map[string]interface{}, encoding nbt.Encoding) { +func (r *Reader) NBT(m *map[string]any, encoding nbt.Encoding) { if err := nbt.NewDecoderWithEncoding(r.r, encoding).Decode(m); err != nil { r.panic(err) } } // NBTList reads a list of NBT tags from the underlying buffer. -func (r *Reader) NBTList(m *[]interface{}, encoding nbt.Encoding) { +func (r *Reader) NBTList(m *[]any, encoding nbt.Encoding) { if err := nbt.NewDecoderWithEncoding(r.r, encoding).Decode(m); err != nil { r.panic(err) } @@ -241,8 +240,8 @@ func (r *Reader) PlayerInventoryAction(x *UseItemTransactionData) { } // EntityMetadata reads an entity metadata map from the underlying buffer into map x. -func (r *Reader) EntityMetadata(x *map[uint32]interface{}) { - *x = map[uint32]interface{}{} +func (r *Reader) EntityMetadata(x *map[uint32]any) { + *x = map[uint32]any{} var count uint32 r.Varuint32(&count) @@ -273,7 +272,7 @@ func (r *Reader) EntityMetadata(x *map[uint32]interface{}) { r.String(&v) (*x)[key] = v case EntityDataCompoundTag: - var v map[string]interface{} + var v map[string]any r.NBT(&v, nbt.NetworkLittleEndian) (*x)[key] = v case EntityDataBlockPos: @@ -297,7 +296,7 @@ func (r *Reader) EntityMetadata(x *map[uint32]interface{}) { // ItemInstance reads an ItemInstance x to the underlying buffer. func (r *Reader) ItemInstance(i *ItemInstance) { x := &i.Stack - x.NBTData = make(map[string]interface{}) + x.NBTData = make(map[string]any) r.Varint32(&x.NetworkID) if x.NetworkID == 0 { // The item was air, so there is no more data we should read for the item instance. After all, air @@ -367,7 +366,7 @@ func (r *Reader) ItemInstance(i *ItemInstance) { // Item reads an ItemStack x from the underlying buffer. func (r *Reader) Item(x *ItemStack) { - x.NBTData = make(map[string]interface{}) + x.NBTData = make(map[string]any) r.Varint32(&x.NetworkID) if x.NetworkID == 0 { // The item was air, so there is no more data we should read for the item instance. After all, air @@ -469,12 +468,12 @@ func (r *Reader) LimitInt32(value int32, min, max int32) { } // UnknownEnumOption panics with an unknown enum option error. -func (r *Reader) UnknownEnumOption(value interface{}, enum string) { +func (r *Reader) UnknownEnumOption(value any, enum string) { r.panicf("unknown value '%v' for enum type '%v'", value, enum) } // InvalidValue panics with an error indicating that the value passed is not valid for a specific field. -func (r *Reader) InvalidValue(value interface{}, forField, reason string) { +func (r *Reader) InvalidValue(value any, forField, reason string) { r.panicf("invalid value '%v' for %v: %v", value, forField, reason) } @@ -561,7 +560,7 @@ func (r *Reader) Varuint32(x *uint32) { } // panicf panics with the format and values passed and assigns the error created to the Reader. -func (r *Reader) panicf(format string, a ...interface{}) { +func (r *Reader) panicf(format string, a ...any) { panic(fmt.Errorf(format, a...)) } diff --git a/minecraft/protocol/skin.go b/minecraft/protocol/skin.go index 38cd43cb9..0c20bfb43 100644 --- a/minecraft/protocol/skin.go +++ b/minecraft/protocol/skin.go @@ -52,9 +52,9 @@ type Skin struct { PrimaryUser bool // CapeID is a unique identifier that identifies the cape. It usually holds a UUID in it. CapeID string - // FullSkinID is an ID that represents the skin in full. The actual functionality is unknown: The client + // FullID is an ID that represents the skin in full. The actual functionality is unknown: The client // does not seem to send a value for this. - FullSkinID string + FullID string // SkinColour is a hex representation (including #) of the base colour of the skin. An example of the // colour sent here is '#b37b62'. SkinColour string @@ -95,7 +95,7 @@ func WriteSerialisedSkin(w *Writer, x *Skin) { w.ByteSlice(&x.GeometryDataEngineVersion) w.ByteSlice(&x.AnimationData) w.String(&x.CapeID) - w.String(&x.FullSkinID) + w.String(&x.FullID) w.String(&x.ArmSize) w.String(&x.SkinColour) l = uint32(len(x.PersonaPieces)) @@ -138,7 +138,7 @@ func SerialisedSkin(r *Reader, x *Skin) { r.ByteSlice(&x.GeometryDataEngineVersion) r.ByteSlice(&x.AnimationData) r.String(&x.CapeID) - r.String(&x.FullSkinID) + r.String(&x.FullID) r.String(&x.ArmSize) r.String(&x.SkinColour) diff --git a/minecraft/protocol/sub_chunk.go b/minecraft/protocol/sub_chunk.go index f78828259..f1d0a73be 100644 --- a/minecraft/protocol/sub_chunk.go +++ b/minecraft/protocol/sub_chunk.go @@ -35,7 +35,7 @@ type SubChunkEntry struct { // HeightMapType is always one of the constants defined in the HeightMapData constants. HeightMapType byte // HeightMapData is the data for the height map. - HeightMapData []byte + HeightMapData []int8 // BlobHash is the hash of the blob. BlobHash uint64 } diff --git a/minecraft/protocol/world.go b/minecraft/protocol/world.go new file mode 100644 index 000000000..a12a226a0 --- /dev/null +++ b/minecraft/protocol/world.go @@ -0,0 +1,30 @@ +package protocol + +const ( + GeneratorLegacy = 0 + GeneratorOverworld = 1 + GeneratorFlat = 2 + GeneratorNether = 3 + GeneratorEnd = 4 + GeneratorVoid = 5 +) + +// DimensionDefinition contains information specifying dimension-specific properties, used for data-driven dimensions. +// These include the range (the height min/max), generator variant, and more. +type DimensionDefinition struct { + // Name specifies the name of the dimension. + Name string + // Range is the height range of the dimension, where the first value is the minimum and the second is the maximum. + Range [2]int32 + // Generator is the variant of generator that exists in the provided dimension. These can be one of the constants + // defined above. If this is set to GeneratorLegacy, the legacy horizontal world limits will be enforced. + Generator int32 +} + +// DimensionDef reads/writes a DimensionDefinition x using IO r. +func DimensionDef(r IO, x *DimensionDefinition) { + r.String(&x.Name) + r.Varint32(&x.Range[0]) + r.Varint32(&x.Range[1]) + r.Varint32(&x.Generator) +} diff --git a/minecraft/protocol/writer.go b/minecraft/protocol/writer.go index 371b6258f..68b3660fe 100644 --- a/minecraft/protocol/writer.go +++ b/minecraft/protocol/writer.go @@ -163,7 +163,7 @@ func (w *Writer) PlayerInventoryAction(x *UseItemTransactionData) { } // EntityMetadata writes an entity metadata map x to the underlying buffer. -func (w *Writer) EntityMetadata(x *map[uint32]interface{}) { +func (w *Writer) EntityMetadata(x *map[uint32]any) { l := uint32(len(*x)) w.Varuint32(&l) @@ -196,7 +196,7 @@ func (w *Writer) EntityMetadata(x *map[uint32]interface{}) { case string: w.Varuint32(&entityDataString) w.String(&v) - case map[string]interface{}: + case map[string]any: w.Varuint32(&entityDataCompoundTag) w.NBT(&v, nbt.NetworkLittleEndian) case BlockPos: @@ -381,30 +381,30 @@ func (w *Writer) Varuint32(x *uint32) { } // NBT writes a map as NBT to the underlying buffer using the encoding passed. -func (w *Writer) NBT(x *map[string]interface{}, encoding nbt.Encoding) { +func (w *Writer) NBT(x *map[string]any, encoding nbt.Encoding) { if err := nbt.NewEncoderWithEncoding(w.w, encoding).Encode(*x); err != nil { panic(err) } } // NBTList writes a slice as NBT to the underlying buffer using the encoding passed. -func (w *Writer) NBTList(x *[]interface{}, encoding nbt.Encoding) { +func (w *Writer) NBTList(x *[]any, encoding nbt.Encoding) { if err := nbt.NewEncoderWithEncoding(w.w, encoding).Encode(*x); err != nil { panic(err) } } // UnknownEnumOption panics with an unknown enum option error. -func (w *Writer) UnknownEnumOption(value interface{}, enum string) { +func (w *Writer) UnknownEnumOption(value any, enum string) { w.panicf("unknown value '%v' for enum type '%v'", value, enum) } // InvalidValue panics with an invalid value error. -func (w *Writer) InvalidValue(value interface{}, forField, reason string) { +func (w *Writer) InvalidValue(value any, forField, reason string) { w.panicf("invalid value '%v' for %v: %v", value, forField, reason) } // panicf panics with the format and values passed. -func (w *Writer) panicf(format string, a ...interface{}) { +func (w *Writer) panicf(format string, a ...any) { panic(fmt.Errorf(format, a...)) } diff --git a/minecraft/resource/pack.go b/minecraft/resource/pack.go index 7087cb3fb..8130a6a28 100644 --- a/minecraft/resource/pack.go +++ b/minecraft/resource/pack.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/muhammadmuzzammil1998/jsonc" "io" - "io/ioutil" "os" "path/filepath" "strconv" @@ -60,7 +59,7 @@ func MustCompile(path string) *Pack { // zip archive and contain a pack manifest in order for the function to succeed. // FromBytes saves the data to a temporary archive. func FromBytes(data []byte) (*Pack, error) { - tempFile, err := ioutil.TempFile("", "resource_pack_archive-*.mcpack") + tempFile, err := os.CreateTemp("", "resource_pack_archive-*.mcpack") if err != nil { return nil, fmt.Errorf("error creating temp zip archive: %v", err) } @@ -236,7 +235,7 @@ func compile(path string) (*Pack, error) { // Then we read the entire content of the zip archive into a byte slice and compute the SHA256 checksum // and a reader. - content, err := ioutil.ReadFile(path) + content, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("error reading resource pack file content: %v", err) } @@ -251,7 +250,7 @@ func compile(path string) (*Pack, error) { func createTempArchive(path string) (*os.File, error) { // We've got a directory which we need to load. Provided we need to send compressed zip data to the // client, we compile it to a zip archive in a temporary file. - temp, err := ioutil.TempFile("", "resource_pack-*.mcpack") + temp, err := os.CreateTemp("", "resource_pack-*.mcpack") if err != nil { return nil, fmt.Errorf("error creating temp zip file: %v", err) } @@ -287,7 +286,7 @@ func createTempArchive(path string) (*os.File, error) { if err != nil { return fmt.Errorf("error opening resource pack file %v: %v", filePath, err) } - data, _ := ioutil.ReadAll(file) + data, _ := io.ReadAll(file) // Write the original content into the 'zip file' so that we write compressed data to the file. if _, err := f.Write(data); err != nil { return fmt.Errorf("error writing file data to zip: %v", err) @@ -345,7 +344,7 @@ func readManifest(path string) (*Manifest, error) { }() // Read all data from the manifest file so that we can decode it into a Manifest struct. - allData, err := ioutil.ReadAll(manifestFile) + allData, err := io.ReadAll(manifestFile) if err != nil { return nil, fmt.Errorf("error reading from manifest file: %v", err) } diff --git a/minecraft/text/colour.go b/minecraft/text/colour.go index d957ce3e9..a5f79a3f1 100644 --- a/minecraft/text/colour.go +++ b/minecraft/text/colour.go @@ -8,7 +8,7 @@ import ( // ANSI converts all Minecraft text formatting codes in the values passed to ANSI formatting codes, so that // it may be displayed properly in the terminal. -func ANSI(a ...interface{}) string { +func ANSI(a ...any) string { str := make([]string, len(a)) for i, v := range a { str[i] = minecraftReplacer.Replace(fmt.Sprint(v)) @@ -22,7 +22,7 @@ func ANSI(a ...interface{}) string { // red, purple, yellow, white, dark-yellow, obfuscated, bold (b), and italic (i). // These HTML tags may also be nested, like so: // `Hello World!` -func Colourf(format string, a ...interface{}) string { +func Colourf(format string, a ...any) string { str := fmt.Sprintf(format, a...) e := &enc{w: &strings.Builder{}, first: true} @@ -52,20 +52,14 @@ func (e *enc) process(tok html.Token) { } switch tok.Type { case html.TextToken: - for _, s := range e.formatStack { - e.w.WriteString(s) - } - e.w.WriteString(tok.Data) - if len(e.formatStack) != 0 { - e.w.WriteString(reset) - } + e.writeText(tok.Data) case html.StartTagToken: if format, ok := strMap[tok.Data]; ok { e.formatStack = append(e.formatStack, format) return } // Not a known colour, so just write the token as a string. - e.w.WriteString("<" + tok.Data + ">") + e.writeText("<" + tok.Data + ">") case html.EndTagToken: for i, format := range e.formatStack { if f, ok := strMap[tok.Data]; ok && f == format { @@ -74,6 +68,17 @@ func (e *enc) process(tok html.Token) { } } // Not a known colour, so just write the token as a string. - e.w.WriteString("") + e.writeText("") + } +} + +// writeText writes text to the encoder by encasing it in the current format stack. +func (e *enc) writeText(s string) { + for _, format := range e.formatStack { + e.w.WriteString(format) + } + e.w.WriteString(s) + if len(e.formatStack) != 0 { + e.w.WriteString(reset) } } diff --git a/mirror/io/assembler/assembler.go b/mirror/io/assembler/assembler.go index cde161dab..44ced3680 100644 --- a/mirror/io/assembler/assembler.go +++ b/mirror/io/assembler/assembler.go @@ -70,6 +70,7 @@ func (o *Assembler) GenRequestFromLevelChunk(pk *packet.LevelChunk) (requests [] requests = append(requests, &packet.SubChunkRequest{ Dimension: 0, Position: protocol.SubChunkPos{pk.Position.X(), int32(i), pk.Position.Z()}, + Offsets: [][3]int8{[3]int8{0,0,0}}, }) } return requests @@ -121,8 +122,8 @@ func (o *Assembler) OnNewSubChunk(pk *packet.SubChunk) *mirror.ChunkData { return } }() - cp := define.ChunkPos{pk.SubChunkX, pk.SubChunkZ} - // subChunkIndex := pk.SubChunkY + cp := define.ChunkPos{pk.Position[0], pk.Position[2]} + // subChunkIndex := pk.Position[1] o.taskMu.RLock() if chunkData, hasK := o.pendingTasks[cp]; !hasK { o.taskMu.RUnlock() @@ -130,20 +131,18 @@ func (o *Assembler) OnNewSubChunk(pk *packet.SubChunk) *mirror.ChunkData { return nil } else { o.taskMu.RUnlock() - if pk.RequestResult != packet.SubChunkRequestResultSuccess { - // cancel pending task - // fmt.Println("Cancel Pending Task") + if pk.SubChunkEntries[0].Result != protocol.SubChunkResultSuccess { o.taskMu.Lock() delete(o.pendingTasks, cp) o.taskMu.Unlock() return nil } - subIndex, subChunk, nbts, err := chunk.NEMCSubChunkDecode(pk.Data) + subIndex, subChunk, nbts, err := chunk.NEMCSubChunkDecode(pk.SubChunkEntries[0].RawPayload) if err != nil { panic(err) } - if subIndex != int8(pk.SubChunkY) || subIndex > 20 { - panic(fmt.Sprintf("sub Index conflict %v %v", pk.SubChunkY, subIndex)) + if subIndex != int8(pk.Position[1]) || subIndex > 20 { + panic(fmt.Sprintf("sub Index conflict %v %v", pk.Position[1], subIndex)) } subs := chunkData.Chunk.Sub() //if subChunk.Empty() { diff --git a/omega/utils/pkt_mapping.go b/omega/utils/pkt_mapping.go index 11a4829a2..52fcbe15f 100644 --- a/omega/utils/pkt_mapping.go +++ b/omega/utils/pkt_mapping.go @@ -181,7 +181,6 @@ func init() { "IDClientStartItemCooldown": packet.IDClientStartItemCooldown, "IDScriptMessage": packet.IDScriptMessage, "IDCodeBuilderSource": packet.IDCodeBuilderSource, - "IDPyRpc": packet.IDPyRpc, } PktIDInvMapping = make(map[int]string) PktIDNames = make([]string, 0) From 16c8754b2b71f0ac665f952f76da01f8839d8f3f Mon Sep 17 00:00:00 2001 From: Ruphane <24724395+LNSSPsd@users.noreply.github.com> Date: Sat, 7 Jan 2023 00:32:29 -0800 Subject: [PATCH 2/4] Support for NEMC v2.5, chunk related stuff is WIP --- fastbuilder/core/core.go | 3 +- io/commands/output.go | 3 +- io/special_tasks/export.go | 4 +- io/special_tasks/lexport.go | 10 +++-- minecraft/dial.go | 6 ++- minecraft/protocol/login/request.go | 2 +- .../packet/client_bound_map_item_data.go | 2 + .../protocol/packet/inventory_content.go | 2 + minecraft/protocol/structure.go | 3 ++ mirror/io/assembler/assembler.go | 2 + omega/mainframe/bootstrap.go | 2 +- omega/mainframe/logo.go | 39 +++++++++++++++++++ 12 files changed, 67 insertions(+), 11 deletions(-) diff --git a/fastbuilder/core/core.go b/fastbuilder/core/core.go index 9cfe63296..5128696d6 100644 --- a/fastbuilder/core/core.go +++ b/fastbuilder/core/core.go @@ -330,7 +330,8 @@ func EnterWorkerThread(env *environment.PBEnvironment, breaker chan struct{}) { /*chunkAssembler.CreateRequestScheduler(func(pk *packet.SubChunkRequest) { conn.WritePacket(pk) })*/ - fmt.Printf("WARNING: TODO: Dump runtime id table, for what chunk loading is currently stubbed\n") + fmt.Printf("WARNING: TODO: Dump runtime id table, for what chunk loading is currently stubbed.\n") + // Also at mirror/io/assembler/assembler.go:119(currently) search "WIP" plz // currentChunkConstructor := &world_provider.ChunkConstructor{} for { if(breaker!=nil) { diff --git a/io/commands/output.go b/io/commands/output.go index 13cd1f4aa..4912ff00a 100644 --- a/io/commands/output.go +++ b/io/commands/output.go @@ -43,11 +43,12 @@ func (sender *CommandSender) Output(content string) error { } msg := strings.Replace(content, "schematic", "sc***atic", -1) msg = strings.Replace(msg, ".", ".", -1) + return sender.SendChat(fmt.Sprintf("§b%s",msg)) // Netease set .bdx, .schematic, .mcacblock, etc as blocked words // So we should replace half-width points w/ full-width points to avoid being // blocked //return SendChat(fmt.Sprintf("§b%s",msg), conn) - return sender.SendSizukanaCommand(TellRawRequest(types.AllPlayers, msg)) + //return sender.SendSizukanaCommand(TellRawRequest(types.AllPlayers, msg)) } func RawTellRawRequest(target types.Target, line string) string { diff --git a/io/special_tasks/export.go b/io/special_tasks/export.go index b1e4a395e..29f7a9a56 100644 --- a/io/special_tasks/export.go +++ b/io/special_tasks/export.go @@ -32,8 +32,8 @@ import ( func CreateExportTask(commandLine string, env *environment.PBEnvironment) *task.Task { cmdsender := env.CommandSender // WIP - //cmdsender.Output("Sorry, but compatibility works haven't been done yet, redirected to lexport.") - //return CreateLegacyExportTask(commandLine, env) + cmdsender.Output("Sorry, but compatibility works haven't been done yet, you are being redirected to lexport.") + return CreateLegacyExportTask(commandLine, env) cfg, err := parsing.Parse(commandLine, configuration.GlobalFullConfig(env).Main()) if err != nil { cmdsender.Output(fmt.Sprintf("Failed to parse command: %v", err)) diff --git a/io/special_tasks/lexport.go b/io/special_tasks/lexport.go index 697017541..2420678c4 100644 --- a/io/special_tasks/lexport.go +++ b/io/special_tasks/lexport.go @@ -75,14 +75,14 @@ func CreateLegacyExportTask(commandLine string, env *environment.PBEnvironment) close(chann) var dimension float64 = 0 var got interface{} - var testAreaIsLoaded string = "testforblocks ~ -64 ~ ~63 319 ~63 ~ -64 ~" + var testAreaIsLoaded string = "testforblocks ~-31 -64 ~-31 ~31 319 ~31 ~-31 -64 ~-31" json.Unmarshal([]byte(resp.OutputMessages[0].Parameters[0]), &got) dimension = got.([]interface{})[0].(map[string]interface{})["dimension"].(float64) if dimension == 1 { - testAreaIsLoaded = "testforblocks ~-16 0 ~-16 ~63 127 ~63 ~ 0 ~" + testAreaIsLoaded = "testforblocks ~-31 0 ~-31 ~31 127 ~31 ~-31 0 ~-31" } if dimension == 2 { - testAreaIsLoaded = "testforblocks ~ 0 ~ ~63 255 ~63 ~ 0 ~" + testAreaIsLoaded = "testforblocks ~-31 0 ~-31 ~31 255 ~31 ~-31 0 ~-31" } // 这个前置准备用于后面判断被导出区域是否加载 // 如果尝试请求一个没有被完全加载的区域,那么返回的结构将是只包括空气的结构,但不会报错 @@ -105,7 +105,7 @@ func CreateLegacyExportTask(commandLine string, env *environment.PBEnvironment) u_d2, _ := uuid.NewUUID() wchan := make(chan *packet.CommandOutput) (*env.CommandSender.GetUUIDMap()).Store(u_d2.String(), wchan) - env.CommandSender.SendWSCommand(fmt.Sprintf("tp %d %d %d", value.BeginX, value.BeginY, value.BeginZ), u_d2) + env.CommandSender.SendWSCommand(fmt.Sprintf("tp %d %d %d", value.BeginX+value.SizeX/2, value.BeginY+value.SizeY/2, value.BeginZ+value.SizeZ/2), u_d2) <-wchan close(wchan) // 传送玩家 @@ -116,6 +116,7 @@ func CreateLegacyExportTask(commandLine string, env *environment.PBEnvironment) env.CommandSender.SendWSCommand(testAreaIsLoaded, u_d3) resp := <-chann close(chann) + //fmt.Printf("%#v\n",resp) if resp.OutputMessages[0].Message == "commands.compare.tooManyBlocks" { break } @@ -136,6 +137,7 @@ func CreateLegacyExportTask(commandLine string, env *environment.PBEnvironment) Mirror: 0, Integrity: 100, Seed: 0, + AllowNonTickingChunks: true, }, RequestType: packet.StructureTemplateRequestExportFromSave, }) diff --git a/minecraft/dial.go b/minecraft/dial.go index e0a11397d..4a5075fce 100644 --- a/minecraft/dial.go +++ b/minecraft/dial.go @@ -1,6 +1,7 @@ package minecraft import ( + "fmt" "bytes" "context" "crypto/ecdsa" @@ -165,7 +166,10 @@ func (d Dialer) DialContext(ctx context.Context, network string) (conn *Conn, er setAndroidData(&conn.clientData) request = login.Encode(chainData, conn.clientData, key) - identityData, _, _, _ := login.Parse(request) + identityData, _, _, err := login.Parse(request) + if err!=nil { + fmt.Printf("WARNING: Identity data parsing error: %w\n", err) + } // If we got the identity data from Minecraft auth, we need to make sure we set it in the Conn too, as // we are not aware of the identity data ourselves yet. conn.identityData = identityData diff --git a/minecraft/protocol/login/request.go b/minecraft/protocol/login/request.go index f94757ee1..c3ef532bd 100644 --- a/minecraft/protocol/login/request.go +++ b/minecraft/protocol/login/request.go @@ -77,7 +77,7 @@ func Parse(request []byte) (IdentityData, ClientData, AuthResult, error) { var identityClaims identityClaims var authenticated bool - t, iss := time.Now(), "Mojang" + t, iss := time.Now(), "NetEase" switch len(req.Chain) { case 1: diff --git a/minecraft/protocol/packet/client_bound_map_item_data.go b/minecraft/protocol/packet/client_bound_map_item_data.go index 930c62c0d..8df4ee571 100644 --- a/minecraft/protocol/packet/client_bound_map_item_data.go +++ b/minecraft/protocol/packet/client_bound_map_item_data.go @@ -134,6 +134,8 @@ func (pk *ClientBoundMapItemData) Marshal(w *protocol.Writer) { // Unmarshal ... func (pk *ClientBoundMapItemData) Unmarshal(r *protocol.Reader) { + // IGNORED !!! + return r.Varint64(&pk.MapID) r.Varuint32(&pk.UpdateFlags) r.Uint8(&pk.Dimension) diff --git a/minecraft/protocol/packet/inventory_content.go b/minecraft/protocol/packet/inventory_content.go index cf82fa838..efc845b3a 100644 --- a/minecraft/protocol/packet/inventory_content.go +++ b/minecraft/protocol/packet/inventory_content.go @@ -36,6 +36,8 @@ func (pk *InventoryContent) Unmarshal(r *protocol.Reader) { var length uint32 r.Varuint32(&pk.WindowID) r.Varuint32(&length) + // IGNORED !!! + return pk.Content = make([]protocol.ItemInstance, length) for i := uint32(0); i < length; i++ { diff --git a/minecraft/protocol/structure.go b/minecraft/protocol/structure.go index 4c4cc2476..c19a4ea99 100644 --- a/minecraft/protocol/structure.go +++ b/minecraft/protocol/structure.go @@ -36,6 +36,8 @@ type StructureSettings struct { // IgnoreBlocks specifies if the structure should ignore blocks or include them. If set to false, blocks // will show up in the exported structure. IgnoreBlocks bool + // See gophertunnel + AllowNonTickingChunks bool // Size is the size of the area that is about to be exported. The area exported will start at the // Position + Offset, and will extend as far as Size specifies. Size BlockPos @@ -70,6 +72,7 @@ func StructSettings(r IO, x *StructureSettings) { r.String(&x.PaletteName) r.Bool(&x.IgnoreEntities) r.Bool(&x.IgnoreBlocks) + r.Bool(&x.AllowNonTickingChunks) r.UBlockPos(&x.Size) r.UBlockPos(&x.Offset) r.Varint64(&x.LastEditingPlayerUniqueID) diff --git a/mirror/io/assembler/assembler.go b/mirror/io/assembler/assembler.go index 44ced3680..fed2d9963 100644 --- a/mirror/io/assembler/assembler.go +++ b/mirror/io/assembler/assembler.go @@ -115,6 +115,8 @@ func (o *Assembler) AddPendingTask(pk *packet.LevelChunk) (exist bool) { } func (o *Assembler) OnNewSubChunk(pk *packet.SubChunk) *mirror.ChunkData { + // WIP + return nil defer func() { r := recover() if r != nil { diff --git a/omega/mainframe/bootstrap.go b/omega/mainframe/bootstrap.go index 7d2a50c36..5e8515d06 100644 --- a/omega/mainframe/bootstrap.go +++ b/omega/mainframe/bootstrap.go @@ -448,7 +448,7 @@ func (o *Omega) Bootstrap(adaptor defines.ConnectionAdaptor) { cb(p.Username) } } - fmt.Println(strings.Join(GetLogo(LOGO_BOTH), "\n")) + fmt.Println(strings.Join(GetWIPLogo(LOGO_BOTH), "\n")) pterm.Success.Println("OMEGA_ng 等待指令") pterm.Success.Println("输入 ? 以获得帮助") if len(updateInfo) > 10 { diff --git a/omega/mainframe/logo.go b/omega/mainframe/logo.go index a8e5b6d4c..cc42ec336 100644 --- a/omega/mainframe/logo.go +++ b/omega/mainframe/logo.go @@ -6,6 +6,45 @@ const ( LOGO_BOTH ) +func GetWIPLogo(mode byte) []string { + image := []string{ + "\033[48;2;88;149;152m\033[38;2;70;155;155m▄\033[48;2;96;163;181m\033[38;2;75;151;161m▄\033[48;2;127;184;216m\033[38;2;123;193;230m▄\033[48;2;111;172;199m\033[38;2;129;192;228m▄\033[48;2;117;193;230m\033[38;2;120;190;224m▄\033[48;2;124;209;252m\033[38;2;98;178;207m▄\033[48;2;90;157;177m\033[38;2;68;141;151m▄\033[48;2;121;180;209m\033[38;2;116;176;203m▄\033[48;2;119;190;224m\033[38;2;118;188;223m▄\033[48;2;114;195;231m\033[38;2;112;197;235m▄\033[48;2;126;201;242m\033[38;2;126;212;255m▄\033[48;2;95;164;186m\033[38;2;76;153;168m▄\033[48;2;90;157;172m\033[38;2;80;150;161m▄\033[48;2;82;150;160m\033[38;2;91;156;171m▄\033[48;2;74;143;151m\033[38;2;96;158;178m▄\033[48;2;124;183;214m\033[38;2;127;182;213m▄\033[48;2;99;151;161m\033[38;2;89;163;173m▄\033[0m", + "\033[48;2;78;161;169m\033[38;2;125;210;253m▄\033[48;2;84;164;185m\033[38;2;124;209;252m▄\033[48;2;123;210;254m\033[38;2;127;213;255m▄\033[48;2;128;196;234m\033[38;2;128;195;231m▄\033[48;2;102;166;190m\033[38;2;128;185;218m▄\033[48;2;72;142;151m\033[38;2;115;175;203m▄\033[48;2;75;148;153m\033[38;2;67;143;158m▄\033[48;2;121;180;205m\033[38;2;116;175;212m▄\033[48;2;96;159;177m\033[38;2;97;165;193m▄\033[48;2;77;154;169m\033[38;2;66;148;162m▄\033[48;2;124;208;244m\033[38;2;73;154;171m▄\033[48;2;77;156;168m\033[38;2;66;140;150m▄\033[48;2;107;170;192m\033[38;2;106;168;193m▄\033[48;2;132;186;220m\033[38;2;113;174;201m▄\033[48;2;122;181;211m\033[38;2;71;142;153m▄\033[48;2;122;180;209m\033[38;2;75;149;158m▄\033[48;2;89;162;171m\033[38;2;72;152;157m▄\033[0m", + "\033[48;2;103;177;203m\033[38;2;90;159;173m▄\033[48;2;123;191;226m\033[38;2;122;179;208m▄\033[48;2;89;167;188m\033[38;2;70;145;152m▄\033[48;2;85;156;171m\033[38;2;66;143;144m▄\033[48;2;103;167;195m\033[38;2;94;163;186m▄\033[48;2;135;185;194m\033[38;2;144;188;190m▄\033[48;2;166;184;53m\033[38;2;204;200;2m▄\033[48;2;177;191;70m\033[38;2;208;205;0m▄\033[48;2;171;188;64m\033[38;2;210;207;0m▄\033[48;2;164;184;50m\033[38;2;210;206;0m▄\033[48;2;165;185;58m\033[38;2;204;200;5m▄\033[48;2;120;174;183m\033[38;2;117;172;169m▄\033[48;2;122;195;237m\033[38;2;120;200;246m▄\033[48;2;109;187;219m\033[38;2;112;197;232m▄\033[48;2;73;151;163m\033[38;2;75;153;165m▄\033[48;2;110;194;230m\033[38;2;127;201;242m▄\033[48;2;115;199;236m\033[38;2;113;193;226m▄\033[0m", + "\033[48;2;99;167;188m\033[38;2;125;192;228m▄\033[48;2;122;188;221m\033[38;2;125;211;255m▄\033[48;2;87;164;182m\033[38;2;128;212;255m▄\033[48;2;75;155;159m\033[38;2;87;164;182m▄\033[48;2;90;161;181m\033[38;2;64;141;154m▄\033[48;2;132;179;176m\033[38;2;94;155;134m▄\033[48;2;196;196;10m\033[38;2;197;197;8m▄\033[48;2;211;212;2m\033[38;2;208;210;2m▄\033[48;2;215;216;3m\033[38;2;213;214;3m▄\033[48;2;210;210;2m\033[38;2;209;210;3m▄\033[48;2;195;196;11m\033[38;2;195;196;12m▄\033[48;2;83;152;133m\033[38;2;93;164;145m▄\033[48;2;97;182;214m\033[38;2;71;157;167m▄\033[48;2;106;188;218m\033[38;2;72;152;160m▄\033[48;2;75;149;159m\033[38;2;77;149;163m▄\033[48;2;124;180;212m\033[38;2;124;183;212m▄\033[48;2;86;156;169m\033[38;2;91;162;173m▄\033[0m", + "\033[48;2;112;173;200m\033[38;2;89;162;171m▄\033[48;2;85;164;186m\033[38;2;74;154;162m▄\033[48;2;129;214;255m\033[38;2;95;177;202m▄\033[48;2;125;192;224m\033[38;2;93;162;186m▄\033[48;2;115;177;211m\033[38;2;110;179;215m▄\033[48;2;132;180;176m\033[38;2;130;198;222m▄\033[48;2;208;202;0m\033[38;2;133;171;97m▄\033[48;2;209;203;0m\033[38;2;130;172;90m▄\033[48;2;207;203;0m\033[38;2;147;182;113m▄\033[48;2;205;200;0m\033[38;2;162;195;140m▄\033[48;2;202;197;0m\033[38;2;158;205;157m▄\033[48;2;84;148;131m\033[38;2;110;171;186m▄\033[48;2;94;177;210m\033[38;2;120;199;241m▄\033[48;2;122;206;241m\033[38;2;123;208;249m▄\033[48;2;120;202;241m\033[38;2;96;177;203m▄\033[48;2;131;188;222m\033[38;2;94;161;181m▄\033[48;2;88;158;169m\033[38;2;100;164;183m▄\033[0m", + "\033[48;2;73;158;155m\033[38;2;75;159;160m▄\033[48;2;76;159;163m\033[38;2;81;164;178m▄\033[48;2;84;165;181m\033[38;2;126;211;255m▄\033[48;2;78;157;178m\033[38;2;128;212;255m▄\033[48;2;104;185;221m\033[38;2;128;212;255m▄\033[48;2;118;205;247m\033[38;2;117;200;236m▄\033[48;2;64;147;170m\033[38;2;77;159;165m▄\033[48;2;63;151;164m\033[38;2;78;161;160m▄\033[48;2;87;162;189m\033[38;2;72;151;156m▄\033[48;2;113;184;232m\033[38;2;86;163;183m▄\033[48;2;119;211;255m\033[38;2;128;210;251m▄\033[48;2;117;183;216m\033[38;2;77;155;174m▄\033[48;2;116;192;225m\033[38;2;71;151;160m▄\033[48;2;99;183;210m\033[38;2;73;155;161m▄\033[48;2;69;148;156m\033[38;2;81;163;174m▄\033[48;2;81;160;179m\033[38;2;126;211;254m▄\033[48;2;116;184;215m\033[38;2;126;210;254m▄\033[0m", + "\033[48;2;89;176;191m\033[38;2;107;159;174m▄\033[48;2;122;206;246m\033[38;2;124;211;254m▄\033[48;2;129;214;255m\033[38;2;94;174;200m▄\033[48;2;89;170;195m\033[38;2;104;170;195m▄\033[48;2;73;152;167m\033[38;2;87;156;172m▄\033[48;2;87;168;189m\033[38;2;79;159;174m▄\033[48;2;122;206;245m\033[38;2;128;212;255m▄\033[48;2;76;158;172m\033[38;2;109;193;225m▄\033[48;2;96;178;205m\033[38;2;98;180;209m▄\033[48;2;128;213;253m\033[38;2;102;180;209m▄\033[48;2;124;210;255m\033[38;2;126;195;232m▄\033[48;2;73;149;168m\033[38;2;105;170;197m▄\033[48;2;102;183;215m\033[38;2;119;196;235m▄\033[48;2;108;190;224m\033[38;2;121;206;248m▄\033[48;2;71;145;160m\033[38;2;105;182;215m▄\033[48;2;124;187;221m\033[38;2;125;184;217m▄\033[48;2;93;168;187m\033[38;2;103;141;152m▄\033[0m", + "", + "", + "", + } + text := []string{ + "\033[1;34;40m┌─────────────────────────────────────────────────┐ \033[0m", + "\033[1;34;40m| ██████ ███ ███ ███████ ██████ █████ | \033[0m", + "\033[1;31;40m|█████████████████████████████████████████████████| \033[0m", + "\033[0;31;40m|█████████████████████████████████████████████████| \033[0m", + "\033[1;31;40m|█████████████████████████████████████████████████| \033[0m", + "\033[1;34;40m| ██████ ██ ██ ███████ ██████ ██ ██ | \033[0m", + "\033[1;34;40m└─────────────────────────────────────────────────┘ \033[0m", + "\033[1;31;40m警告:兼容工作尚未完成,现在使用可能会出现各类问题!\033[0m", + "\033[1;31;40m警告:兼容工作尚未完成,现在使用可能会出现各类问题!\033[0m", + "\033[1;31;40m警告:兼容工作尚未完成,现在使用可能会出现各类问题!\033[0m", + } + if mode == LOGO_TEXT_ONLY { + return text + } else if mode == LOGO_IMAGE_ONLY { + return image + } else { + o := []string{} + for i := 0; i < 10; i++ { + o = append(o, image[i]+"\u001B[1;34;40m \u001B[0m"+text[i]) + } + return o + } + +} + func GetLogo(mode byte) []string { image := []string{ "\033[48;2;88;149;152m\033[38;2;70;155;155m▄\033[48;2;96;163;181m\033[38;2;75;151;161m▄\033[48;2;127;184;216m\033[38;2;123;193;230m▄\033[48;2;111;172;199m\033[38;2;129;192;228m▄\033[48;2;117;193;230m\033[38;2;120;190;224m▄\033[48;2;124;209;252m\033[38;2;98;178;207m▄\033[48;2;90;157;177m\033[38;2;68;141;151m▄\033[48;2;121;180;209m\033[38;2;116;176;203m▄\033[48;2;119;190;224m\033[38;2;118;188;223m▄\033[48;2;114;195;231m\033[38;2;112;197;235m▄\033[48;2;126;201;242m\033[38;2;126;212;255m▄\033[48;2;95;164;186m\033[38;2;76;153;168m▄\033[48;2;90;157;172m\033[38;2;80;150;161m▄\033[48;2;82;150;160m\033[38;2;91;156;171m▄\033[48;2;74;143;151m\033[38;2;96;158;178m▄\033[48;2;124;183;214m\033[38;2;127;182;213m▄\033[48;2;99;151;161m\033[38;2;89;163;173m▄\033[0m", From b4d04e5a08e7405ae2a7c97b57fe9209ea95dc16 Mon Sep 17 00:00:00 2001 From: Ruphane <24724395+LNSSPsd@users.noreply.github.com> Date: Sat, 7 Jan 2023 00:41:34 -0800 Subject: [PATCH 3/4] Bump version: 4.9.95001 Containing no ability on resolving chunks, which is still WIP --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index 0c89fc927..e599f35eb 100644 --- a/version +++ b/version @@ -1 +1 @@ -4.0.0 \ No newline at end of file +4.9.95001 \ No newline at end of file From b3e6292faecd1235966ba0dfc93dd483e794381a Mon Sep 17 00:00:00 2001 From: Ruphane <24724395+LNSSPsd@users.noreply.github.com> Date: Sat, 7 Jan 2023 01:02:21 -0800 Subject: [PATCH 4/4] Update packetType.go --- fastbuilder/script_engine/packetType.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastbuilder/script_engine/packetType.go b/fastbuilder/script_engine/packetType.go index 0e5513610..eecc2118b 100644 --- a/fastbuilder/script_engine/packetType.go +++ b/fastbuilder/script_engine/packetType.go @@ -168,7 +168,7 @@ func init() { "IDAddVolumeEntity": packet.IDAddVolumeEntity, "IDRemoveVolumeEntity": packet.IDRemoveVolumeEntity, // "IDNeteaseJson": packet.IDNeteaseJson, - "IDPyRpc": packet.IDPyRpc, + //"IDPyRpc": packet.IDPyRpc, } bridge.PacketNameMap=PacketNameMap }