Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial support for v1.19.30 #146

Merged
merged 29 commits into from Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
1fa4932
gophertunnel: Experimental implementation of v1.19.30.
JustTalDevelops Aug 18, 2022
269cd84
packet/encoder.go: Removed unused interface.
JustTalDevelops Aug 18, 2022
ee3208f
protocol/compression.go: Moved to the packet package.
JustTalDevelops Aug 18, 2022
684763f
minecraft/conn.go: Properly handle NetworkSettings packets.
JustTalDevelops Aug 18, 2022
dc63707
protocol/item_stack.go: Added ItemStackRequest filter causes.
JustTalDevelops Aug 18, 2022
ce37dcf
minecraft/conn.go: ClientSideGeneration is now usable.
JustTalDevelops Aug 18, 2022
d4e121e
Merge branch 'master' into feature/v1.19.30
Sandertv Sep 5, 2022
2a73b83
packet/compression.go: Make FlateCompression use sync.Pools again for…
Sandertv Sep 5, 2022
b3e3dd9
packet/compression.go: Better error for snappy decompression failure.
Sandertv Sep 5, 2022
23b5c81
packet/text.go: Added new `ObjectAnnouncement` text type.
JustTalDevelops Sep 5, 2022
3e932e5
packet/structure_block_update.go: Added missing 'Waterlogged' field.
JustTalDevelops Sep 5, 2022
ecda8cd
packet/level_sound_event.go: Added 'EnchantingTableUse' sound event.
JustTalDevelops Sep 5, 2022
a6e97db
packet: Removed various useless 'undefined' constants.
JustTalDevelops Sep 5, 2022
248ba2d
packet/ability.go: Generalized AbilityData into a single struct.
JustTalDevelops Sep 5, 2022
a10a1d4
protocol/info.go: Bump protocol to 553.
JustTalDevelops Sep 5, 2022
7fb1569
Merge remote-tracking branch 'origin/master' into feature/v1.19.30
JustTalDevelops Sep 6, 2022
a7c8e10
protocol: Support the new encoding/decoding options for ItemDescriptors.
JustTalDevelops Sep 12, 2022
1b9524f
protocol/item_descriptor.go: Fixed InvalidItemDescriptor marshaling.
JustTalDevelops Sep 12, 2022
64ab0c6
go.mod, go.sum: Use RakNet version 11.
JustTalDevelops Sep 12, 2022
15b712d
protocol/command.go: Updated command argument IDs.
JustTalDevelops Sep 13, 2022
24519d3
packet: Improved documentation on new packets.
JustTalDevelops Sep 15, 2022
552ab55
Merge remote-tracking branch 'origin/feature/v1.19.30' into feature/v…
JustTalDevelops Sep 15, 2022
f52bb87
protocol: Updated for v544.
JustTalDevelops Sep 16, 2022
c83a95f
protocol/info.go: Correct protocol version.
JustTalDevelops Sep 16, 2022
c52ba03
packet/network_settings.go: Correct docs.
JustTalDevelops Sep 16, 2022
263b952
protocol/info.go: Current protocol is 554, not 544.
JustTalDevelops Sep 16, 2022
12f490b
packet/structure_block_update.go: Improved documentation.
JustTalDevelops Sep 19, 2022
b27107c
Merge remote-tracking branch 'origin/feature/v1.19.30' into feature/v…
JustTalDevelops Sep 19, 2022
e6a145b
gophertunnel: Resolved review comments.
JustTalDevelops Sep 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions go.mod
Expand Up @@ -4,6 +4,7 @@ go 1.18

require (
github.com/go-gl/mathgl v1.0.0
github.com/golang/snappy v0.0.4
github.com/google/uuid v1.3.0
github.com/klauspost/compress v1.15.1
github.com/muhammadmuzzammil1998/jsonc v1.0.0
Expand All @@ -24,3 +25,5 @@ require (
google.golang.org/appengine v1.6.6 // indirect
google.golang.org/protobuf v1.25.0 // indirect
)

replace github.com/sandertv/go-raknet => github.com/justtaldevelops/go-raknet v0.0.0-20220912200218-80153477b5b0
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
6 changes: 4 additions & 2 deletions go.sum
Expand Up @@ -78,6 +78,8 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand Down Expand Up @@ -107,6 +109,8 @@ github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/justtaldevelops/go-raknet v0.0.0-20220912200218-80153477b5b0 h1:uQ+mkJqPu7m6wczUg9wogBhTcrRgK51Fc8LBaRRdPzs=
github.com/justtaldevelops/go-raknet v0.0.0-20220912200218-80153477b5b0/go.mod h1:Gx+WgZBMQ0V2UoouGoJ8Wj6CDrMBQ4SB2F/ggpl5/+Y=
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=
Expand All @@ -121,8 +125,6 @@ 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.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=
Expand Down
17 changes: 0 additions & 17 deletions internal/pool.go
Expand Up @@ -2,26 +2,9 @@ package internal

import (
"bytes"
"github.com/klauspost/compress/flate"
"io"
"sync"
)

// DecompressPool is a sync.Pool for io.ReadCloser flate readers. These are pooled for connections.
var DecompressPool = sync.Pool{
New: func() any {
return flate.NewReader(bytes.NewReader(nil))
},
}

// CompressPool is a sync.Pool for writeCloseResetter flate readers. These are pooled for connections.
var CompressPool = sync.Pool{
New: func() any {
w, _ := flate.NewWriter(io.Discard, 6)
return w
},
}

// BufferPool is a sync.Pool for buffers used to write compressed data to.
var BufferPool = sync.Pool{
New: func() any {
Expand Down
78 changes: 54 additions & 24 deletions minecraft/conn.go
Expand Up @@ -93,6 +93,9 @@ type Conn struct {
bufferedSend [][]byte
hdr *packet.Header

// readyToLogin is a bool indicating if the connection is ready to login. This is used to ensure that the client
// has received the relevant network settings before the login sequence starts.
readyToLogin bool
// loggedIn is a bool indicating if the connection was logged in. It is set to true after the entire login
// sequence is completed.
loggedIn bool
Expand Down Expand Up @@ -148,7 +151,7 @@ func newConn(netConn net.Conn, key *ecdsa.PrivateKey, log *log.Logger) *Conn {
log: log,
hdr: &packet.Header{},
}
conn.expectedIDs.Store([]uint32{packet.IDLogin})
conn.expectedIDs.Store([]uint32{packet.IDRequestNetworkSettings})
_, _ = rand.Read(conn.salt)

go func() {
Expand Down Expand Up @@ -602,6 +605,8 @@ func (conn *Conn) handlePacket(pk packet.Packet) error {
}()
switch pk := pk.(type) {
// Internal packets destined for the server.
case *packet.RequestNetworkSettings:
return conn.handleRequestNetworkSettings(pk)
case *packet.Login:
return conn.handleLogin(pk)
case *packet.ClientToServerHandshake:
Expand All @@ -618,6 +623,8 @@ func (conn *Conn) handlePacket(pk packet.Packet) error {
return conn.handleSetLocalPlayerAsInitialised(pk)

// Internal packets destined for the client.
case *packet.NetworkSettings:
return conn.handleNetworkSettings(pk)
case *packet.ServerToClientHandshake:
return conn.handleServerToClientHandshake(pk)
case *packet.PlayStatus:
Expand All @@ -638,26 +645,9 @@ func (conn *Conn) handlePacket(pk packet.Packet) error {
return nil
}

// handleLogin handles an incoming login packet. It verifies an decodes the login request found in the packet
// and returns an error if it couldn't be done successfully.
func (conn *Conn) handleLogin(pk *packet.Login) error {
// The next expected packet is a response from the client to the handshake.
conn.expect(packet.IDClientToServerHandshake)
var (
err error
authResult login.AuthResult
)
conn.identityData, conn.clientData, authResult, err = login.Parse(pk.ConnectionRequest)
if err != nil {
return fmt.Errorf("parse login request: %w", err)
}

// Make sure the player is logged in with XBOX Live when necessary.
if !authResult.XBOXLiveAuthenticated && conn.authEnabled {
_ = conn.WritePacket(&packet.Disconnect{Message: text.Colourf("<red>You must be logged in with XBOX Live to join.</red>")})
return fmt.Errorf("connection %v was not authenticated to XBOX Live", conn.RemoteAddr())
}

// handleRequestNetworkSettings handles an incoming RequestNetworkSettings packet. It returns an error if the protocol
// version is not supported, otherwise sending back a NetworkSettings packet.
func (conn *Conn) handleRequestNetworkSettings(pk *packet.RequestNetworkSettings) error {
found := false
for _, pro := range conn.acceptedProto {
if pro.ID() == pk.ClientProtocol {
Expand All @@ -676,6 +666,47 @@ func (conn *Conn) handleLogin(pk *packet.Login) error {
_ = conn.WritePacket(&packet.PlayStatus{Status: status})
return fmt.Errorf("%v connected with an incompatible protocol: expected protocol = %v, client protocol = %v", conn.identityData.DisplayName, protocol.CurrentProtocol, pk.ClientProtocol)
}

conn.expect(packet.IDLogin)
if err := conn.WritePacket(&packet.NetworkSettings{
CompressionThreshold: 512,
CompressionAlgorithm: packet.SnappyCompression{},
}); err != nil {
return fmt.Errorf("error sending network settings: %v", err)
}
_ = conn.Flush()
conn.enc.EnableCompression(packet.SnappyCompression{})
conn.dec.EnableCompression(packet.SnappyCompression{})
return nil
}

// handleNetworkSettings handles an incoming NetworkSettings packet, enabling compression for future packets.
func (conn *Conn) handleNetworkSettings(pk *packet.NetworkSettings) error {
conn.enc.EnableCompression(pk.CompressionAlgorithm)
conn.dec.EnableCompression(pk.CompressionAlgorithm)
conn.readyToLogin = true
return nil
}

// handleLogin handles an incoming login packet. It verifies and decodes the login request found in the packet
// and returns an error if it couldn't be done successfully.
func (conn *Conn) handleLogin(pk *packet.Login) error {
// The next expected packet is a response from the client to the handshake.
conn.expect(packet.IDClientToServerHandshake)
var (
err error
authResult login.AuthResult
)
conn.identityData, conn.clientData, authResult, err = login.Parse(pk.ConnectionRequest)
if err != nil {
return fmt.Errorf("parse login request: %w", err)
}

// Make sure the player is logged in with XBOX Live when necessary.
if !authResult.XBOXLiveAuthenticated && conn.authEnabled {
_ = conn.WritePacket(&packet.Disconnect{Message: text.Colourf("<red>You must be logged in with XBOX Live to join.</red>")})
return fmt.Errorf("connection %v was not authenticated to XBOX Live", conn.RemoteAddr())
}
if err := conn.enableEncryption(authResult.PublicKey); err != nil {
return fmt.Errorf("error enabling encryption: %v", err)
}
Expand All @@ -686,9 +717,6 @@ func (conn *Conn) handleLogin(pk *packet.Login) error {
func (conn *Conn) handleClientToServerHandshake() error {
// The next expected packet is a resource pack client response.
conn.expect(packet.IDResourcePackClientResponse, packet.IDClientCacheStatus)
if err := conn.WritePacket(&packet.NetworkSettings{CompressionThreshold: 512}); err != nil {
return fmt.Errorf("error sending network settings: %v", err)
}
if err := conn.WritePacket(&packet.PlayStatus{Status: packet.PlayStatusLoginSuccess}); err != nil {
return fmt.Errorf("error sending play status login success: %v", err)
}
Expand Down Expand Up @@ -1129,6 +1157,7 @@ func (conn *Conn) handleStartGame(pk *packet.StartGame) error {
conn.gameData = GameData{
Difficulty: pk.Difficulty,
WorldName: pk.WorldName,
WorldSeed: pk.WorldSeed,
EntityUniqueID: pk.EntityUniqueID,
EntityRuntimeID: pk.EntityRuntimeID,
PlayerGameMode: pk.PlayerGameMode,
Expand All @@ -1151,6 +1180,7 @@ func (conn *Conn) handleStartGame(pk *packet.StartGame) error {
ServerAuthoritativeInventory: pk.ServerAuthoritativeInventory,
ChatRestrictionLevel: pk.ChatRestrictionLevel,
DisablePlayerInteractions: pk.DisablePlayerInteractions,
ClientSideGeneration: pk.ClientSideGeneration,
Experiments: pk.Experiments,
}
for _, item := range pk.Items {
Expand Down
43 changes: 32 additions & 11 deletions minecraft/dial.go
Expand Up @@ -187,28 +187,44 @@ func (d Dialer) DialContext(ctx context.Context, network, address string) (conn
// we are not aware of the identity data ourselves yet.
conn.identityData = identityData
}
c := make(chan struct{})
go listenConn(conn, d.ErrorLog, c)

conn.expect(packet.IDServerToClientHandshake, packet.IDPlayStatus)
if err := conn.WritePacket(&packet.Login{ConnectionRequest: request, ClientProtocol: d.Protocol.ID()}); err != nil {
l, c := make(chan struct{}), make(chan struct{})
go listenConn(conn, d.ErrorLog, l, c)

conn.expect(packet.IDNetworkSettings)
if err := conn.WritePacket(&packet.RequestNetworkSettings{ClientProtocol: d.Protocol.ID()}); err != nil {
return nil, err
}
_ = conn.Flush()

select {
case <-conn.close:
return nil, conn.closeErr("dial")
case <-ctx.Done():
return nil, conn.wrap(ctx.Err(), "dial")
case <-c:
// We've connected successfully. We return the connection and no error.
return conn, nil
case <-l:
// We've received our network settings, so we can now send our login request.
conn.expect(packet.IDServerToClientHandshake, packet.IDPlayStatus)
if err := conn.WritePacket(&packet.Login{ConnectionRequest: request, ClientProtocol: d.Protocol.ID()}); err != nil {
return nil, err
}
_ = conn.Flush()

select {
case <-conn.close:
return nil, conn.closeErr("dial")
case <-ctx.Done():
return nil, conn.wrap(ctx.Err(), "dial")
case <-c:
// We've connected successfully. We return the connection and no error.
return conn, nil
}
}
}

// listenConn listens on the connection until it is closed on another goroutine. The channel passed will
// receive a value once the connection is logged in.
func listenConn(conn *Conn, logger *log.Logger, c chan struct{}) {
func listenConn(conn *Conn, logger *log.Logger, l, c chan struct{}) {
defer func() {
_ = conn.Close()
}()
Expand All @@ -223,14 +239,19 @@ func listenConn(conn *Conn, logger *log.Logger, c chan struct{}) {
return
}
for _, data := range packets {
loggedInBefore := conn.loggedIn
loggedInBefore, readyToLoginBefore := conn.loggedIn, conn.readyToLogin
if err := conn.receive(data); err != nil {
logger.Printf("error: %v", err)
return
}
if !readyToLoginBefore && conn.readyToLogin {
// This is the signal that the connection is ready to login, so we put a value in the channel so that
// it may be detected.
l <- struct{}{}
}
if !loggedInBefore && conn.loggedIn {
// This is the signal that the connection was considered logged in, so we put a value in the
// channel so that it may be detected.
// This is the signal that the connection was considered logged in, so we put a value in the channel so
// that it may be detected.
c <- struct{}{}
}
}
Expand Down
23 changes: 23 additions & 0 deletions minecraft/protocol/ability.go
Expand Up @@ -34,6 +34,29 @@ const (
AbilityBaseWalkSpeed = 0.1
)

// AbilityData represents various data about the abilities of a player, such as ability layers or permissions.
type AbilityData struct {
// EntityUniqueID is a unique identifier of the player. It appears it is not required to fill this field
// out with a correct value. Simply writing 0 seems to work.
EntityUniqueID int64
// PlayerPermissions is the permission level of the player as it shows up in the player list built up using
// the PlayerList packet.
PlayerPermissions byte
// CommandPermissions is a set of permissions that specify what commands a player is allowed to execute.
CommandPermissions byte
// Layers contains all ability layers and their potential values. This should at least have one entry, being the
// base layer.
Layers []AbilityLayer
}

// Marshal encodes/decodes an AbilityData.
func (x *AbilityData) Marshal(r IO) {
r.Int64(&x.EntityUniqueID)
r.Uint8(&x.PlayerPermissions)
r.Uint8(&x.CommandPermissions)
SliceUint8Length(r, &x.Layers)
}

// AbilityLayer represents the abilities of a specific layer, such as the base layer or the spectator layer.
type AbilityLayer struct {
// Type represents the type of the layer. This is one of the AbilityLayerType constants defined above.
Expand Down
34 changes: 19 additions & 15 deletions minecraft/protocol/command.go
Expand Up @@ -42,21 +42,25 @@ const (
CommandArgSuffixed = 0x1000000
CommandArgSoftEnum = 0x4000000

CommandArgTypeInt = 1
CommandArgTypeFloat = 3
CommandArgTypeValue = 4
CommandArgTypeWildcardInt = 5
CommandArgTypeOperator = 6
CommandArgTypeTarget = 8
CommandArgTypeWildcardTarget = 10
CommandArgTypeFilepath = 17
CommandArgTypeString = 39
CommandArgTypeBlockPosition = 47
CommandArgTypePosition = 48
CommandArgTypeMessage = 51
CommandArgTypeRawText = 53
CommandArgTypeJSON = 57
CommandArgTypeCommand = 70
CommandArgTypeInt = 1
CommandArgTypeFloat = 3
CommandArgTypeValue = 4
CommandArgTypeWildcardInt = 5
CommandArgTypeOperator = 6
CommandArgTypeCompareOperator = 7
CommandArgTypeTarget = 8
CommandArgTypeWildcardTarget = 10
CommandArgTypeFilepath = 17
CommandArgTypeIntegerRange = 23
CommandArgTypeEquipmentSlots = 38
CommandArgTypeString = 39
CommandArgTypeBlockPosition = 47
CommandArgTypePosition = 48
CommandArgTypeMessage = 51
CommandArgTypeRawText = 53
CommandArgTypeJSON = 57
CommandArgTypeBlockStates = 67
CommandArgTypeCommand = 70
)
const (
// ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not,
Expand Down
4 changes: 2 additions & 2 deletions minecraft/protocol/info.go
Expand Up @@ -2,7 +2,7 @@ package protocol

const (
// CurrentProtocol is the current protocol version for the version below.
CurrentProtocol = 545
CurrentProtocol = 554
// CurrentVersion is the current version of Minecraft as supported by the `packet` package.
CurrentVersion = "1.19.21"
CurrentVersion = "1.19.30"
)
1 change: 1 addition & 0 deletions minecraft/protocol/io.go
Expand Up @@ -45,6 +45,7 @@ type IO interface {
EntityMetadata(x *map[uint32]any)
Item(x *ItemStack)
ItemInstance(i *ItemInstance)
ItemDescriptorCount(i *ItemDescriptorCount)
MaterialReducer(x *MaterialReducer)
GameRule(x *GameRule)

Expand Down