diff --git a/go.mod b/go.mod index d7f7a3c2..11f4cb06 100644 --- a/go.mod +++ b/go.mod @@ -6,10 +6,9 @@ require ( github.com/go-gl/mathgl v1.0.0 github.com/google/uuid v1.3.0 github.com/klauspost/compress v1.15.1 - github.com/kr/pretty v0.1.0 github.com/muhammadmuzzammil1998/jsonc v1.0.0 github.com/pelletier/go-toml v1.9.4 - github.com/sandertv/go-raknet v1.10.9 + github.com/sandertv/go-raknet v1.11.1 go.uber.org/atomic v1.9.0 golang.org/x/net v0.0.0-20220418201149-a630d4f3e7a2 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 @@ -20,7 +19,6 @@ require ( require ( github.com/df-mc/atomic v1.10.0 // indirect github.com/golang/protobuf v1.4.2 // indirect - github.com/kr/text v0.1.0 // indirect golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect google.golang.org/appengine v1.6.6 // indirect diff --git a/go.sum b/go.sum index bae1b827..6950777a 100644 --- a/go.sum +++ b/go.sum @@ -110,10 +110,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.1 h1:y9FcTHGyrebwfP0ZZqFiaxTaiDnUrGkJkI+f583BL1A= github.com/klauspost/compress v1.15.1/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/muhammadmuzzammil1998/jsonc v1.0.0 h1:8o5gBQn4ZA3NBA9DlTujCj2a4w0tqWrPVjDwhzkgTIs= github.com/muhammadmuzzammil1998/jsonc v1.0.0/go.mod h1:saF2fIVw4banK0H4+/EuqfFLpRnoy5S+ECwTOCcRcSU= @@ -123,8 +121,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/sandertv/go-raknet v1.10.9 h1:1a8ntIenpDBue3IsUdhJhxTznGt8Qeaan7HtQKi0hBs= -github.com/sandertv/go-raknet v1.10.9/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y= +github.com/sandertv/go-raknet v1.11.1 h1:0auvhHoZNyC/Z1l5xqniE3JE+w3MGO3n3JXEGHzdlRE= +github.com/sandertv/go-raknet v1.11.1/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= diff --git a/minecraft/conn.go b/minecraft/conn.go index e1b14a6a..cb117208 100644 --- a/minecraft/conn.go +++ b/minecraft/conn.go @@ -68,7 +68,6 @@ type Conn struct { gameData GameData gameDataReceived atomic.Bool - chunkRadius int // privateKey is the private key of this end of the connection. Each connection, regardless of which side // the connection is on, server or client, has a unique private key generated. @@ -137,18 +136,17 @@ type Conn struct { // key is generated. func newConn(netConn net.Conn, key *ecdsa.PrivateKey, log *log.Logger) *Conn { conn := &Conn{ - enc: packet.NewEncoder(netConn), - dec: packet.NewDecoder(netConn), - salt: make([]byte, 16), - packets: make(chan *packetData, 8), - additional: make(chan packet.Packet, 16), - close: make(chan struct{}), - spawn: make(chan struct{}), - conn: netConn, - privateKey: key, - log: log, - chunkRadius: 16, - hdr: &packet.Header{}, + enc: packet.NewEncoder(netConn), + dec: packet.NewDecoder(netConn), + salt: make([]byte, 16), + packets: make(chan *packetData, 8), + additional: make(chan packet.Packet, 16), + close: make(chan struct{}), + spawn: make(chan struct{}), + conn: netConn, + privateKey: key, + log: log, + hdr: &packet.Header{}, } conn.expectedIDs.Store([]uint32{packet.IDLogin}) _, _ = rand.Read(conn.salt) @@ -505,7 +503,7 @@ func (conn *Conn) ClientCacheEnabled() bool { // Listener, this is the radius that the client requested. For connections obtained through a Dialer, this // is the radius that the server approved upon. func (conn *Conn) ChunkRadius() int { - return conn.chunkRadius + return int(conn.gameData.ChunkRadius) } // takeDeferredPacket locks the deferred packets lock and takes the next packet from the list of deferred @@ -660,14 +658,16 @@ func (conn *Conn) handleLogin(pk *packet.Login) error { return fmt.Errorf("connection %v was not authenticated to XBOX Live", conn.RemoteAddr()) } + found := false for _, pro := range conn.acceptedProto { if pro.ID() == pk.ClientProtocol { conn.proto = pro conn.pool = pro.Packets() + found = true break } } - if conn.proto == nil { + if !found { status := packet.PlayStatusLoginFailedClient if pk.ClientProtocol > protocol.CurrentProtocol { // The server is outdated in this case, so we have to change the status we send. @@ -1120,7 +1120,6 @@ func (conn *Conn) handleResourcePackChunkRequest(pk *packet.ResourcePackChunkReq // handleStartGame handles an incoming StartGame packet. It is the signal that the player has been added to a // world, and it obtains most of its dedicated properties. func (conn *Conn) handleStartGame(pk *packet.StartGame) error { - conn.gameDataReceived.Store(true) conn.gameData = GameData{ Difficulty: pk.Difficulty, WorldName: pk.WorldName, @@ -1150,10 +1149,8 @@ func (conn *Conn) handleStartGame(pk *packet.StartGame) error { } } - conn.loggedIn = true - conn.waitingForSpawn.Store(true) + _ = conn.WritePacket(&packet.RequestChunkRadius{ChunkRadius: 16}) conn.expect(packet.IDChunkRadiusUpdated, packet.IDPlayStatus) - _ = conn.WritePacket(&packet.RequestChunkRadius{ChunkRadius: int32(conn.chunkRadius)}) return nil } @@ -1164,8 +1161,12 @@ func (conn *Conn) handleRequestChunkRadius(pk *packet.RequestChunkRadius) error return fmt.Errorf("requested chunk radius must be at least 1, got %v", pk.ChunkRadius) } conn.expect(packet.IDSetLocalPlayerAsInitialised) - _ = conn.WritePacket(&packet.ChunkRadiusUpdated{ChunkRadius: pk.ChunkRadius}) - conn.chunkRadius = int(pk.ChunkRadius) + radius := pk.ChunkRadius + if r := conn.gameData.ChunkRadius; r != 0 { + radius = r + } + _ = conn.WritePacket(&packet.ChunkRadiusUpdated{ChunkRadius: radius}) + conn.gameData.ChunkRadius = pk.ChunkRadius // The client crashes when not sending all biomes, due to achievements assuming all biomes are present. //noinspection SpellCheckingInspection @@ -1192,7 +1193,12 @@ func (conn *Conn) handleChunkRadiusUpdated(pk *packet.ChunkRadiusUpdated) error return fmt.Errorf("new chunk radius must be at least 1, got %v", pk.ChunkRadius) } conn.expect(packet.IDPlayStatus) - conn.chunkRadius = int(pk.ChunkRadius) + + conn.gameData.ChunkRadius = pk.ChunkRadius + conn.gameDataReceived.Store(true) + conn.loggedIn = true + conn.waitingForSpawn.Store(true) + return nil } diff --git a/minecraft/game_data.go b/minecraft/game_data.go index 5b2d151a..9be62eb9 100644 --- a/minecraft/game_data.go +++ b/minecraft/game_data.go @@ -76,4 +76,7 @@ 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 + // ChunkRadius is the initial chunk radius that the connection gets. This can be changed later on using a + // packet.ChunkRadiusUpdated. + ChunkRadius int32 } diff --git a/minecraft/protocol/login/data.go b/minecraft/protocol/login/data.go index dd7c59fe..aa51d9b4 100644 --- a/minecraft/protocol/login/data.go +++ b/minecraft/protocol/login/data.go @@ -105,6 +105,8 @@ type ClientData struct { // GUIScale is the GUI scale of the player. It is by default 0, and is otherwise -1 or -2 for a smaller // GUI scale than usual. GUIScale int `json:"GuiScale"` + // IsEditorMode is a value to dictate if the player is in editor mode. + IsEditorMode bool // LanguageCode is the language code of the player. It looks like 'en_UK'. It follows the ISO language // codes, but hyphens ('-') are replaced with underscores. ('_') LanguageCode string