From 3f8f85aa1d3325b00f189cc0a11d41766bc13618 Mon Sep 17 00:00:00 2001 From: Rainchi <35858349+rain931215@users.noreply.github.com> Date: Tue, 23 Jun 2020 17:26:48 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=8C=87=E5=AE=9A=E7=95=B6=E5=82=B3?= =?UTF-8?q?=E9=80=81=E5=8A=A0=E5=85=A5=E4=BC=BA=E6=9C=8D=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E8=AB=8B=E6=B1=82=E8=87=B3Mojang=E6=99=82=E7=9A=84Content-Type?= =?UTF-8?q?=E6=A8=99=E9=A0=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 官方好像正常是要指定Content-Type( https://wiki.vg/Authentication#Request_format ) 現在是不加沒關係 但如果Mojang修正的話可能會出錯 --- bot/login.go | 1 + 1 file changed, 1 insertion(+) diff --git a/bot/login.go b/bot/login.go index 8469ad2..63d1596 100644 --- a/bot/login.go +++ b/bot/login.go @@ -185,6 +185,7 @@ func loginAuth(AsTk, name, UUID string, shareSecret []byte, er encryptionRequest } PostRequest.Header.Set("User-agent", "go-mc") PostRequest.Header.Set("Connection", "keep-alive") + PostRequest.Header.Set("Content-Type", "application/json") resp, err := client.Do(PostRequest) if err != nil { return fmt.Errorf("post fail: %v", err) From b602b7b3e0cc808d122488a7c93ae651afac18ae Mon Sep 17 00:00:00 2001 From: Tnze Date: Tue, 30 Jun 2020 23:35:11 +0800 Subject: [PATCH 2/5] example server. close #61 --- cmd/simpleServer/main.go | 153 +++++++++++++++++++++++++++++++++++++ cmd/simpleServer/status.go | 64 ++++++++++++++++ 2 files changed, 217 insertions(+) create mode 100644 cmd/simpleServer/main.go create mode 100644 cmd/simpleServer/status.go diff --git a/cmd/simpleServer/main.go b/cmd/simpleServer/main.go new file mode 100644 index 0000000..e3daffb --- /dev/null +++ b/cmd/simpleServer/main.go @@ -0,0 +1,153 @@ +// Example minecraft 1.15.2 server +package main + +import ( + "github.com/Tnze/go-mc/bot" + "github.com/Tnze/go-mc/data" + "github.com/Tnze/go-mc/net" + pk "github.com/Tnze/go-mc/net/packet" + "github.com/google/uuid" + "log" +) + +const ProtocolVersion = 578 +const Threshold = 256 +const MaxPlayer = 200 + +func main() { + l, err := net.ListenMC(":25565") + if err != nil { + log.Fatalf("Listen error: %v", err) + } + + for { + conn, err := l.Accept() + if err != nil { + log.Fatalf("Accept error: %v", err) + } + go acceptConn(conn) + } +} + +func acceptConn(conn net.Conn) { + defer conn.Close() + // handshake + protocol, intention, err := handshake(conn) + if err != nil { + log.Printf("Handshake error: %v", err) + return + } + + switch intention { + default: //unknown error + log.Printf("Unknown handshake intention: %v", intention) + case 1: //for status + acceptListPing(conn) + case 2: //for login + handlePlaying(conn, protocol) + } +} + +func handlePlaying(conn net.Conn, protocol int32) { + // login, get player info + info, err := acceptLogin(conn) + if err != nil { + log.Print("Login failed") + return + } + + // Write LoginSuccess packet + err = loginSuccess(conn, info.Name, info.UUID) + if err != nil { + log.Print("Login failed on success") + return + } + + joinGame(conn) + conn.WritePacket(pk.Marshal(data.PlayerPositionAndLookClientbound, + // https://wiki.vg/Protocol#Player_Position_And_Look_.28clientbound.29 + pk.Double(0), pk.Double(0), pk.Double(0), // XYZ + pk.Float(0), pk.Float(0), // Yaw Pitch + pk.Byte(0), // flag + pk.VarInt(0), // TP ID + )) + // Just for block this goroutine. Keep the connection + for { + if _, err := conn.ReadPacket(); err != nil { + log.Printf("ReadPacket error: %v", err) + break + } + // KeepAlive packet is not handled, so client might + // exit because of "time out". + } +} + +type PlayerInfo struct { + Name string + UUID uuid.UUID + OPLevel int +} + +// acceptLogin check player's account +func acceptLogin(conn net.Conn) (info PlayerInfo, err error) { + //login start + var p pk.Packet + p, err = conn.ReadPacket() + if err != nil { + return + } + + err = p.Scan((*pk.String)(&info.Name)) //decode username as pk.String + if err != nil { + return + } + + //auth + const OnlineMode = false + if OnlineMode { + log.Panic("Not Implement") + } else { + // offline-mode UUID + info.UUID = bot.OfflineUUID(info.Name) + } + + return +} + +// handshake receive and parse Handshake packet +func handshake(conn net.Conn) (protocol, intention int32, err error) { + var ( + Protocol, Intention pk.VarInt + ServerAddress pk.String // ignored + ServerPort pk.UnsignedShort // ignored + ) + // receive handshake packet + p, err := conn.ReadPacket() + if err != nil { + return 0, 0, err + } + err = p.Scan(&Protocol, &ServerAddress, &ServerPort, &Intention) + return int32(Protocol), int32(Intention), err +} + +// loginSuccess send LoginSuccess packet to client +func loginSuccess(conn net.Conn, name string, uuid uuid.UUID) error { + return conn.WritePacket(pk.Marshal(0x02, + pk.String(uuid.String()), //uuid as string with hyphens + pk.String(name), + )) +} + +func joinGame(conn net.Conn) error { + return conn.WritePacket(pk.Marshal(data.JoinGame, + pk.Int(0), // EntityID + pk.UnsignedByte(1), // Gamemode + pk.Int(0), // Dimension + pk.Long(0), // HashedSeed + pk.UnsignedByte(MaxPlayer), // MaxPlayer + pk.String("default"), // LevelType + pk.VarInt(15), // View Distance + pk.Boolean(false), // Reduced Debug Info + pk.Boolean(true), // Enable respawn screen + )) +} diff --git a/cmd/simpleServer/status.go b/cmd/simpleServer/status.go new file mode 100644 index 0000000..9cb2831 --- /dev/null +++ b/cmd/simpleServer/status.go @@ -0,0 +1,64 @@ +package main + +import ( + "encoding/json" + "github.com/Tnze/go-mc/chat" + "github.com/Tnze/go-mc/net" + pk "github.com/Tnze/go-mc/net/packet" + "github.com/google/uuid" + "log" +) + +func acceptListPing(conn net.Conn) { + for i := 0; i < 2; i++ { // ping or list. Only accept twice + p, err := conn.ReadPacket() + if err != nil { + return + } + + switch p.ID { + case 0x00: //List + err = conn.WritePacket(pk.Marshal(0x00, pk.String(listResp()))) + case 0x01: //Ping + err = conn.WritePacket(p) + } + if err != nil { + return + } + } +} + +type player struct { + Name string `json:"name"` + ID uuid.UUID `json:"id"` +} + +// listResp return server status as JSON string +func listResp() string { + var list struct { + Version struct { + Name string `json:"name"` + Protocol int `json:"protocol"` + } `json:"version"` + Players struct { + Max int `json:"max"` + Online int `json:"online"` + Sample []player `json:"sample"` + } `json:"players"` + Description chat.Message `json:"description"` + FavIcon string `json:"favicon,omitempty"` + } + + list.Version.Name = "Chat Server" + list.Version.Protocol = ProtocolVersion + list.Players.Max = MaxPlayer + list.Players.Online = 123 + list.Players.Sample = []player{} // must init. can't be nil + list.Description = chat.Message{Text: "Powered by go-mc", Color: "blue"} + + data, err := json.Marshal(list) + if err != nil { + log.Panic("Marshal JSON for status checking fail") + } + return string(data) +} From 32a6898b12d2f3424097fcc6ddae41752f531f07 Mon Sep 17 00:00:00 2001 From: genanik Date: Wed, 1 Jul 2020 09:48:26 +0800 Subject: [PATCH 3/5] Update packetIDs to 1.16 --- bot/ingame.go | 5 +++-- data/packetIDs.go | 52 +++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/bot/ingame.go b/bot/ingame.go index afa2cbc..5b35398 100644 --- a/bot/ingame.go +++ b/bot/ingame.go @@ -274,8 +274,9 @@ func handleSetSlotPacket(c *Client, p pk.Packet) error { func handleChatMessagePacket(c *Client, p pk.Packet) (err error) { var ( - s chat.Message - pos pk.Byte + s chat.Message + pos pk.Byte + sender pk.UUID ) err = p.Scan(&s, &pos) diff --git a/data/packetIDs.go b/data/packetIDs.go index 2f349d0..7e3493e 100644 --- a/data/packetIDs.go +++ b/data/packetIDs.go @@ -4,26 +4,25 @@ package data const ( SpawnObject byte = iota //0x00 SpawnExperienceOrb - SpawnGlobalEntity - SpawnMob + SpawnLivingEntity SpawnPainting SpawnPlayer - AnimationClientbound + EntityAnimationClientbound Statistics AcknowledgePlayerDigging BlockBreakAnimation - UpdateBlockEntity + BlockEntityData BlockAction BlockChange BossBar ServerDifficulty ChatMessageClientbound + MultiBlockChange - MultiBlockChange //0x10 - TabComplete + TabComplete //0x10 DeclareCommands - ConfirmTransaction - CloseWindow + WindowConfirmationClientbound + CloseWindowClientbound WindowItems WindowProperty SetSlot @@ -35,14 +34,14 @@ const ( Explosion UnloadChunk ChangeGameState + OpenHorseWindow - OpenHorseWindow //0x20 - KeepAliveClientbound - ChunkData + KeepAliveClientbound //0x20 + ChunkData // TODO Pre Effect Particle UpdateLight - JoinGame + JoinGame // TODO Pre MapData TradeList EntityRelativeMove @@ -52,9 +51,9 @@ const ( VehicleMoveClientbound OpenBook OpenWindow + OpenSignEditor - OpenSignEditor //0x30 - CraftRecipeResponse + CraftRecipeResponse //0x30 PlayerAbilitiesClientbound CombatEvent PlayerInfo @@ -69,10 +68,11 @@ const ( SelectAdvancementTab WorldBorder Camera + HeldItemChangeClientbound - HeldItemChangeClientbound //0x40 - UpdateViewPosition + UpdateViewPosition //0x40 UpdateViewDistance + SpawnPosition DisplayScoreboard EntityMetadata AttachEntity @@ -84,11 +84,10 @@ const ( SetPassengers Teams UpdateScore - SpawnPosition TimeUpdate + Title - Title //0x50 - EntitySoundEffect + EntitySoundEffect //0x50 SoundEffect StopSound PlayerListHeaderAndFooter @@ -98,8 +97,8 @@ const ( Advancements EntityProperties EntityEffect - DeclareRecipes - Tags //0x5C + DeclareRecipes // TODO Pre + Tags //0x5B ) // Serverbound packet IDs @@ -119,9 +118,10 @@ const ( EditBook QueryEntityNBT UseEntity - KeepAliveServerbound + GenerateStructure - LockDifficulty //0x10 + KeepAliveServerbound //0x10 + LockDifficulty PlayerPosition PlayerPositionAndLookServerbound PlayerLook @@ -136,9 +136,9 @@ const ( SteerVehicle RecipeBookData NameItem - ResourcePackStatus - AdvancementTab //0x20 + ResourcePackStatus //0x20 + AdvancementTab SelectTrade SetBeaconEffect HeldItemChangeServerbound @@ -151,5 +151,5 @@ const ( AnimationServerbound Spectate PlayerBlockPlacement - UseItem //0x2D + UseItem //0x2E ) From 444229216a786c4372fe7895f8ca914df0e810b3 Mon Sep 17 00:00:00 2001 From: genanik Date: Wed, 1 Jul 2020 11:32:58 +0800 Subject: [PATCH 4/5] Basic support for 1.16.1 --- bot/client.go | 13 ++++++++----- bot/event.go | 2 +- bot/ingame.go | 28 ++++++++++++++++++++-------- bot/mcbot.go | 2 +- cmd/daze/daze.go | 2 +- data/packetIDs.go | 8 ++++---- 6 files changed, 35 insertions(+), 20 deletions(-) diff --git a/bot/client.go b/bot/client.go index fe052ba..1a28952 100644 --- a/bot/client.go +++ b/bot/client.go @@ -49,13 +49,16 @@ func NewClient() (c *Client) { //PlayInfo content player info in server. type PlayInfo struct { - Gamemode int //游戏模式 - Hardcore bool //是否是极限模式 - Dimension int //维度 - Difficulty int //难度 - LevelType string //地图类型 + Gamemode int //游戏模式 + Hardcore bool //是否是极限模式 + Dimension int //维度 + Difficulty int //难度 + // LevelType string //地图类型 1.16删了 ViewDistance int //视距 ReducedDebugInfo bool //减少调试信息 + WorldName string //当前世界的名字 + IsDebug bool //调试 + IsFlat bool //超平坦世界 // SpawnPosition Position //主世界出生点 } diff --git a/bot/event.go b/bot/event.go index d121c05..d3ba7dc 100644 --- a/bot/event.go +++ b/bot/event.go @@ -9,7 +9,7 @@ import ( type eventBroker struct { GameStart func() error - ChatMsg func(msg chat.Message, pos byte) error + ChatMsg func(msg chat.Message, pos byte, sender string) error Disconnect func(reason chat.Message) error HealthChange func() error Die func() error diff --git a/bot/ingame.go b/bot/ingame.go index 5b35398..39b44c9 100644 --- a/bot/ingame.go +++ b/bot/ingame.go @@ -279,13 +279,13 @@ func handleChatMessagePacket(c *Client, p pk.Packet) (err error) { sender pk.UUID ) - err = p.Scan(&s, &pos) + err = p.Scan(&s, &pos, &sender) if err != nil { return err } if c.Events.ChatMsg != nil { - err = c.Events.ChatMsg(s, byte(pos)) + err = c.Events.ChatMsg(s, byte(pos), string(sender.Encode())) } return err @@ -327,17 +327,25 @@ func handleUpdateHealthPacket(c *Client, p pk.Packet) (err error) { func handleJoinGamePacket(c *Client, p pk.Packet) error { var ( - eid pk.Int - gamemode pk.UnsignedByte + eid pk.Int + gamemode pk.UnsignedByte + previousGm pk.UnsignedByte + worldCount pk.VarInt + worldNames pk.Identifier + _ pk.NBT + //dimensionCodec pk.NBT dimension pk.Int + worldName pk.Identifier hashedSeed pk.Long maxPlayers pk.UnsignedByte - levelType pk.String viewDistance pk.VarInt rdi pk.Boolean // Reduced Debug Info ers pk.Boolean // Enable respawn screen + isDebug pk.Boolean + isFlat pk.Boolean ) - err := p.Scan(&eid, &gamemode, &dimension, &hashedSeed, &maxPlayers, &levelType, &rdi, &ers) + err := p.Scan(&eid, &gamemode, &previousGm, &worldCount, &worldNames, &dimension, &worldName, + &hashedSeed, &maxPlayers, &rdi, &ers, &isDebug, &isFlat) if err != nil { return err } @@ -346,9 +354,12 @@ func handleJoinGamePacket(c *Client, p pk.Packet) error { c.Gamemode = int(gamemode & 0x7) c.Hardcore = gamemode&0x8 != 0 c.Dimension = int(dimension) - c.LevelType = string(levelType) + c.WorldName = string(worldName) c.ViewDistance = int(viewDistance) c.ReducedDebugInfo = bool(rdi) + c.IsDebug = bool(isDebug) + c.IsFlat = bool(isFlat) + return nil } @@ -442,13 +453,14 @@ func handleChunkDataPacket(c *Client, p pk.Packet) error { var ( X, Z pk.Int FullChunk pk.Boolean + IgnoreOldData pk.Boolean PrimaryBitMask pk.VarInt Heightmaps struct{} Biomes = biomesData{fullChunk: (*bool)(&FullChunk)} Data chunkData BlockEntities blockEntities ) - if err := p.Scan(&X, &Z, &FullChunk, &PrimaryBitMask, pk.NBT{V: &Heightmaps}, &Biomes, &Data, &BlockEntities); err != nil { + if err := p.Scan(&X, &Z, &FullChunk, &IgnoreOldData, &PrimaryBitMask, pk.NBT{V: &Heightmaps}, &Biomes, &Data, &BlockEntities); err != nil { return err } chunk, err := world.DecodeChunkColumn(int32(PrimaryBitMask), Data) diff --git a/bot/mcbot.go b/bot/mcbot.go index cdf7f47..16dadc6 100644 --- a/bot/mcbot.go +++ b/bot/mcbot.go @@ -13,7 +13,7 @@ import ( ) // ProtocolVersion , the protocol version number of minecraft net protocol -const ProtocolVersion = 578 +const ProtocolVersion = 736 // JoinServer connect a Minecraft server for playing the game. func (c *Client) JoinServer(addr string, port int) (err error) { diff --git a/cmd/daze/daze.go b/cmd/daze/daze.go index 69d6e89..acdd252 100644 --- a/cmd/daze/daze.go +++ b/cmd/daze/daze.go @@ -38,7 +38,7 @@ func onGameStart() error { return nil //if err isn't nil, HandleGame() will return it. } -func onChatMsg(c chat.Message, pos byte) error { +func onChatMsg(c chat.Message, pos byte, uuid string) error { log.Println("Chat:", c.ClearString()) // output chat message without any format code (like color or bold) return nil } diff --git a/data/packetIDs.go b/data/packetIDs.go index 7e3493e..18b4690 100644 --- a/data/packetIDs.go +++ b/data/packetIDs.go @@ -37,11 +37,11 @@ const ( OpenHorseWindow KeepAliveClientbound //0x20 - ChunkData // TODO Pre + ChunkData Effect Particle UpdateLight - JoinGame // TODO Pre + JoinGame MapData TradeList EntityRelativeMove @@ -97,8 +97,8 @@ const ( Advancements EntityProperties EntityEffect - DeclareRecipes // TODO Pre - Tags //0x5B + DeclareRecipes + Tags //0x5B ) // Serverbound packet IDs From e7cfd4bbc6a0efe6be31a89b784ad47966779c2d Mon Sep 17 00:00:00 2001 From: genanik Date: Wed, 1 Jul 2020 13:05:56 +0800 Subject: [PATCH 5/5] fix autofish.go --- cmd/autofish/autofish.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/autofish/autofish.go b/cmd/autofish/autofish.go index bb9bde5..741f8ea 100644 --- a/cmd/autofish/autofish.go +++ b/cmd/autofish/autofish.go @@ -72,7 +72,7 @@ func onSound(name string, category int, x, y, z float64, volume, pitch float32) return nil } -func onChatMsg(c chat.Message, pos byte) error { +func onChatMsg(c chat.Message, pos byte, uuid string) error { log.Println("Chat:", c) return nil }