Add support for protocol version 800 (1.21.80)

Introduced support for protocol 800, including biome definitions, camera presets, and player list updates. Upgraded dependencies, adjusted mappings, and enhanced the README to reflect recent changes.
This commit is contained in:
AkmalFairuz
2025-05-11 21:32:37 +07:00
parent bcb3e990d3
commit 8a209b75bf
14 changed files with 9454 additions and 14 deletions

View File

@@ -5,6 +5,7 @@ A gophertunnel protocol interface implementation to support older Minecraft Bedr
## Supported Versions
| Protocol ID | Version | Support |
|-------------|---------|---------|
| 800 | 1.21.80 | ✅ |
| 786 | 1.21.70 | ✅ |
| 776 | 1.21.60 | ✅ |
| 766 | 1.21.50 | ✅ |
@@ -16,11 +17,10 @@ A gophertunnel protocol interface implementation to support older Minecraft Bedr
| 671 | 1.20.80 | ✅ |
| 662 | 1.20.70 | ✅ |
| 649 | 1.20.60 | ✅ |
| 630 | 1.20.50 | 🚧 |
| 622 | 1.20.40 | 🚧 |
| 618 | 1.20.30 | 🚧 |
| 594 | 1.20.10 | 🚧 |
| 589 | 1.20.0 | 🚧 |
<= 1.20.50 is not possible to support due to different compression logic and gophertunnel does not provide a way to
support dynamic compression.
## Credits
- [Flonja/multiversion](https://github.com/Flonja/multiversion)

16
go.mod
View File

@@ -1,6 +1,8 @@
module github.com/akmalfairuz/legacy-version
go 1.23.3
go 1.24
toolchain go1.24.0
require (
github.com/df-mc/dragonfly v0.10.3
@@ -10,23 +12,23 @@ require (
github.com/pelletier/go-toml v1.9.5
github.com/rogpeppe/go-internal v1.14.1
github.com/samber/lo v1.49.1
github.com/sandertv/gophertunnel v1.45.1
github.com/sandertv/gophertunnel v1.46.1-0.20250511074107-85599aa3447c
github.com/segmentio/fasthash v1.0.3
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394
golang.org/x/image v0.25.0
golang.org/x/oauth2 v0.28.0
golang.org/x/oauth2 v0.30.0
)
require (
github.com/brentp/intintmap v0.0.0-20190211203843-30dc0ade9af9 // indirect
github.com/df-mc/goleveldb v1.1.9 // indirect
github.com/go-jose/go-jose/v4 v4.0.5 // indirect
github.com/go-jose/go-jose/v4 v4.1.0 // indirect
github.com/golang/snappy v1.0.0 // indirect
github.com/klauspost/compress v1.18.0 // indirect
github.com/muhammadmuzzammil1998/jsonc v1.0.0 // indirect
github.com/sandertv/go-raknet v1.14.3-0.20250305181847-6af3e95113d6 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/mod v0.24.0 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/text v0.25.0 // indirect
)

14
go.sum
View File

@@ -17,12 +17,15 @@ github.com/go-gl/mathgl v1.2.0 h1:v2eOj/y1B2afDxF6URV1qCYmo1KW08lAMtTbOn3KXCY=
github.com/go-gl/mathgl v1.2.0/go.mod h1:pf9+b5J3LFP7iZ4XXaVzZrCle0Q/vNpB/vDe5+3ulRE=
github.com/go-jose/go-jose/v4 v4.0.5 h1:M6T8+mKZl/+fNNuFHvGIzDz7BTLQPIounk/b9dw3AaE=
github.com/go-jose/go-jose/v4 v4.0.5/go.mod h1:s3P1lRrkT8igV8D9OjyL4WRyHvjB6a4JSllnOrmmBOA=
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -51,12 +54,16 @@ github.com/sandertv/go-raknet v1.14.3-0.20250305181847-6af3e95113d6 h1:ZfK7NCzID
github.com/sandertv/go-raknet v1.14.3-0.20250305181847-6af3e95113d6/go.mod h1:/yysjwfCXm2+2OY8mBazLzcxJ3irnylKCyG3FLgUPVU=
github.com/sandertv/gophertunnel v1.45.1 h1:mQCEG1Rv1RR9UTRyTu0+XZ/cr3lyWvo/RX0DMHh8S6w=
github.com/sandertv/gophertunnel v1.45.1/go.mod h1:lvzOdyb2fkoo3uySe++hy4UKq0I649oUFJKkro2ZHpY=
github.com/sandertv/gophertunnel v1.46.1-0.20250511074107-85599aa3447c h1:cZlIS07gnBMXJlwJPxGMTPytg2kBXZcYCasxlqPX480=
github.com/sandertv/gophertunnel v1.46.1-0.20250511074107-85599aa3447c/go.mod h1:lvzOdyb2fkoo3uySe++hy4UKq0I649oUFJKkro2ZHpY=
github.com/segmentio/fasthash v1.0.3 h1:EI9+KE1EwvMLBWwjpRDc+fEM+prwxDYbslddQGtrmhM=
github.com/segmentio/fasthash v1.0.3/go.mod h1:waKX8l2N8yckOgmSsXJi7x1ZfdKZ4x7KRMzBtS3oedY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo=
golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
golang.org/x/exp v0.0.0-20250305212735-054e65f0b394 h1:nDVHiLt8aIbd/VzvPWN6kSOPE7+F/fNFDSXLVYkE/Iw=
@@ -72,15 +79,22 @@ golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc=
golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=

View File

@@ -5,6 +5,7 @@ import "github.com/sandertv/gophertunnel/minecraft"
// All returns a slice of all legacy protocol versions that are supported.
func All() []minecraft.Protocol {
return []minecraft.Protocol{
New786(),
New776(),
New766(),
New748(),

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
package legacypacket
import (
"encoding/base64"
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/samber/lo"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
// BiomeDefinitionList is sent by the server to let the client know all biomes that are available and
// implemented on the server side. When enabled, it also includes information for the client to
// accurately recreate the server-side generation in vanilla worlds/servers for increased performance.
type BiomeDefinitionList struct {
// BiomeDefinitions is a list of biomes that are available on the server.
BiomeDefinitions []protocol.BiomeDefinition
// StringList is a makeshift dictionary implementation Mojang created to try and reduce the size of the
// overall packet. It is a list of common strings that are used in the biome definitions, such as
// biome names, float values or query expressions.
StringList []string
}
// ID ...
func (*BiomeDefinitionList) ID() uint32 {
return packet.IDBiomeDefinitionList
}
func (pk *BiomeDefinitionList) Marshal(io protocol.IO) {
if proto.IsProtoGTE(io, proto.ID800) {
protocol.Slice(io, &pk.BiomeDefinitions)
protocol.FuncSlice(io, &pk.StringList, io.String)
} else {
io.Bytes(lo.ToPtr(append([]byte(nil), rawOldSerializedBiomeDefinitionList...)))
}
}
var rawOldSerializedBiomeDefinitionList []byte
func init() {
const s = `CgAKDWJhbWJvb19qdW5nbGUFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoTYmFtYm9vX2p1bmdsZV9oaWxscwUIZG93bmZhbGxmZmY/BQt0ZW1wZXJhdHVyZTMzcz8ACgViZWFjaAUIZG93bmZhbGzNzMw+BQt0ZW1wZXJhdHVyZc3MTD8ACgxiaXJjaF9mb3Jlc3QFCGRvd25mYWxsmpkZPwULdGVtcGVyYXR1cmWamRk/AAoSYmlyY2hfZm9yZXN0X2hpbGxzBQhkb3duZmFsbJqZGT8FC3RlbXBlcmF0dXJlmpkZPwAKGmJpcmNoX2ZvcmVzdF9oaWxsc19tdXRhdGVkBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKFGJpcmNoX2ZvcmVzdF9tdXRhdGVkBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKCmNvbGRfYmVhY2gFCGRvd25mYWxsmpmZPgULdGVtcGVyYXR1cmXNzEw9AAoKY29sZF9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACgpjb2xkX3RhaWdhBQhkb3duZmFsbM3MzD4FC3RlbXBlcmF0dXJlAAAAvwAKEGNvbGRfdGFpZ2FfaGlsbHMFCGRvd25mYWxszczMPgULdGVtcGVyYXR1cmUAAAC/AAoSY29sZF90YWlnYV9tdXRhdGVkBQhkb3duZmFsbM3MzD4FC3RlbXBlcmF0dXJlAAAAvwAKD2RlZXBfY29sZF9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8AChFkZWVwX2Zyb3plbl9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAAChNkZWVwX2x1a2V3YXJtX29jZWFuBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAPwAKCmRlZXBfb2NlYW4FCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAAA/AAoPZGVlcF93YXJtX29jZWFuBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAPwAKBmRlc2VydAUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAACgxkZXNlcnRfaGlsbHMFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoOZGVzZXJ0X211dGF0ZWQFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoNZXh0cmVtZV9oaWxscwUIZG93bmZhbGyamZk+BQt0ZW1wZXJhdHVyZc3MTD4AChJleHRyZW1lX2hpbGxzX2VkZ2UFCGRvd25mYWxsmpmZPgULdGVtcGVyYXR1cmXNzEw+AAoVZXh0cmVtZV9oaWxsc19tdXRhdGVkBQhkb3duZmFsbJqZmT4FC3RlbXBlcmF0dXJlzcxMPgAKGGV4dHJlbWVfaGlsbHNfcGx1c190cmVlcwUIZG93bmZhbGyamZk+BQt0ZW1wZXJhdHVyZc3MTD4ACiBleHRyZW1lX2hpbGxzX3BsdXNfdHJlZXNfbXV0YXRlZAUIZG93bmZhbGyamZk+BQt0ZW1wZXJhdHVyZc3MTD4ACg1mbG93ZXJfZm9yZXN0BQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKBmZvcmVzdAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZTMzMz8ACgxmb3Jlc3RfaGlsbHMFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUzMzM/AAoMZnJvemVuX29jZWFuBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAAAAKDGZyb3plbl9yaXZlcgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAACgRoZWxsBQhkb3duZmFsbAAAAAAFC3RlbXBlcmF0dXJlAAAAQAAKDWljZV9tb3VudGFpbnMFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAAAAAAoKaWNlX3BsYWlucwUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAAChFpY2VfcGxhaW5zX3NwaWtlcwUIZG93bmZhbGwAAIA/BQt0ZW1wZXJhdHVyZQAAAAAACgZqdW5nbGUFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoLanVuZ2xlX2VkZ2UFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUzM3M/AAoTanVuZ2xlX2VkZ2VfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZTMzcz8ACgxqdW5nbGVfaGlsbHMFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoOanVuZ2xlX211dGF0ZWQFCGRvd25mYWxsZmZmPwULdGVtcGVyYXR1cmUzM3M/AAoTbGVnYWN5X2Zyb3plbl9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAAAACg5sdWtld2FybV9vY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACgptZWdhX3RhaWdhBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlmpmZPgAKEG1lZ2FfdGFpZ2FfaGlsbHMFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmWamZk+AAoEbWVzYQUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAACgptZXNhX2JyeWNlBQhkb3duZmFsbAAAAAAFC3RlbXBlcmF0dXJlAAAAQAAKDG1lc2FfcGxhdGVhdQUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAAChRtZXNhX3BsYXRlYXVfbXV0YXRlZAUIZG93bmZhbGwAAAAABQt0ZW1wZXJhdHVyZQAAAEAAChJtZXNhX3BsYXRlYXVfc3RvbmUFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoabWVzYV9wbGF0ZWF1X3N0b25lX211dGF0ZWQFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAABAAAoPbXVzaHJvb21faXNsYW5kBQhkb3duZmFsbAAAgD8FC3RlbXBlcmF0dXJlZmZmPwAKFW11c2hyb29tX2lzbGFuZF9zaG9yZQUIZG93bmZhbGwAAIA/BQt0ZW1wZXJhdHVyZWZmZj8ACgVvY2VhbgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACgZwbGFpbnMFCGRvd25mYWxszczMPgULdGVtcGVyYXR1cmXNzEw/AAobcmVkd29vZF90YWlnYV9oaWxsc19tdXRhdGVkBQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlmpmZPgAKFXJlZHdvb2RfdGFpZ2FfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZQAAgD4ACgVyaXZlcgUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZQAAAD8ACg1yb29mZWRfZm9yZXN0BQhkb3duZmFsbM3MTD8FC3RlbXBlcmF0dXJlMzMzPwAKFXJvb2ZlZF9mb3Jlc3RfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZTMzMz8ACgdzYXZhbm5hBQhkb3duZmFsbAAAAAAFC3RlbXBlcmF0dXJlmpmZPwAKD3NhdmFubmFfbXV0YXRlZAUIZG93bmZhbGwAAAA/BQt0ZW1wZXJhdHVyZc3MjD8ACg9zYXZhbm5hX3BsYXRlYXUFCGRvd25mYWxsAAAAAAULdGVtcGVyYXR1cmUAAIA/AAoXc2F2YW5uYV9wbGF0ZWF1X211dGF0ZWQFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAIA/AAoLc3RvbmVfYmVhY2gFCGRvd25mYWxsmpmZPgULdGVtcGVyYXR1cmXNzEw+AAoQc3VuZmxvd2VyX3BsYWlucwUIZG93bmZhbGzNzMw+BQt0ZW1wZXJhdHVyZc3MTD8ACglzd2FtcGxhbmQFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmXNzEw/AAoRc3dhbXBsYW5kX211dGF0ZWQFCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmXNzEw/AAoFdGFpZ2EFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUAAIA+AAoLdGFpZ2FfaGlsbHMFCGRvd25mYWxszcxMPwULdGVtcGVyYXR1cmUAAIA+AAoNdGFpZ2FfbXV0YXRlZAUIZG93bmZhbGzNzEw/BQt0ZW1wZXJhdHVyZQAAgD4ACgd0aGVfZW5kBQhkb3duZmFsbAAAAD8FC3RlbXBlcmF0dXJlAAAAPwAKCndhcm1fb2NlYW4FCGRvd25mYWxsAAAAPwULdGVtcGVyYXR1cmUAAAA/AAA=`
rawOldSerializedBiomeDefinitionList, _ = base64.StdEncoding.DecodeString(s)
}

View File

@@ -0,0 +1,49 @@
package legacypacket
import (
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
const (
PlayerListActionAdd = iota
PlayerListActionRemove
)
// PlayerList is sent by the server to update the client-side player list in the in-game menu screen. It shows
// the icon of each player if the correct XUID is written in the packet.
// Sending the PlayerList packet is obligatory when sending an AddPlayer packet. The added player will not
// show up to a client if it has not been added to the player list, because several properties of the player
// are obtained from the player list, such as the skin.
type PlayerList struct {
// ActionType is the action to execute upon the player list. The entries that follow specify which entries
// are added or removed from the player list.
ActionType byte
// Entries is a list of all player list entries that should be added/removed from the player list,
// depending on the ActionType set.
Entries []proto.PlayerListEntry
}
// ID ...
func (*PlayerList) ID() uint32 {
return packet.IDPlayerList
}
// Marshal ...
func (pk *PlayerList) Marshal(io protocol.IO) {
io.Uint8(&pk.ActionType)
switch pk.ActionType {
case PlayerListActionAdd:
protocol.Slice(io, &pk.Entries)
case PlayerListActionRemove:
protocol.FuncIOSlice(io, &pk.Entries, proto.PlayerListRemoveEntry)
default:
io.UnknownEnumOption(pk.ActionType, "player list action type")
}
if pk.ActionType == PlayerListActionAdd {
for i := 0; i < len(pk.Entries); i++ {
io.Bool(&pk.Entries[i].Skin.Trusted)
}
}
}

View File

@@ -55,6 +55,18 @@ type CameraPreset struct {
AlignTargetAndCameraForward protocol.Optional[bool]
// AimAssist defines the aim assist to use when using this preset.
AimAssist protocol.Optional[protocol.CameraPresetAimAssist]
// ControlScheme is the control scheme that the client should use in this camera. It is one of the following:
// - ControlSchemeLockedPlayerRelativeStrafe is the default behaviour, this cannot be set when the client
// is in a custom camera.
// - ControlSchemeCameraRelative makes movement relative to the camera's transform, with the client's
// rotation being relative to the client's movement.
// - ControlSchemeCameraRelativeStrafe makes movement relative to the camera's transform, with the
// client's rotation being locked.
// - ControlSchemePlayerRelative makes movement relative to the player's transform, meaning holding
// left/right will make the player turn in a circle.
// - ControlSchemePlayerRelativeStrafe makes movement the same as the default behaviour, but can be
// used in a custom camera.
ControlScheme protocol.Optional[byte]
}
func (x *CameraPreset) FromLatest(cp protocol.CameraPreset) CameraPreset {
@@ -78,6 +90,7 @@ func (x *CameraPreset) FromLatest(cp protocol.CameraPreset) CameraPreset {
x.PlayerEffects = cp.PlayerEffects
x.AlignTargetAndCameraForward = cp.AlignTargetAndCameraForward
x.AimAssist = cp.AimAssist
x.ControlScheme = cp.ControlScheme
return *x
}
@@ -105,6 +118,7 @@ func (x *CameraPreset) ToLatest() protocol.CameraPreset {
PlayerEffects: x.PlayerEffects,
AlignTargetAndCameraForward: x.AlignTargetAndCameraForward,
AimAssist: x.AimAssist,
ControlScheme: x.ControlScheme,
}
}
@@ -146,4 +160,7 @@ func (x *CameraPreset) Marshal(r protocol.IO) {
if IsProtoGTE(r, ID766) {
protocol.OptionalMarshaler(r, &x.AimAssist)
}
if IsProtoGTE(r, ID800) {
protocol.OptionalFunc(r, &x.ControlScheme, r.Uint8)
}
}

View File

@@ -3,6 +3,7 @@ package proto
import "github.com/sandertv/gophertunnel/minecraft/protocol"
const (
ID800 = 800 // v1.21.80
ID786 = 786 // v1.21.70
ID776 = 776 // v1.21.60
ID766 = 766 // v1.21.50

97
legacyver/proto/player.go Normal file
View File

@@ -0,0 +1,97 @@
package proto
import (
"github.com/google/uuid"
"github.com/sandertv/gophertunnel/minecraft/protocol"
)
// PlayerListEntry is an entry found in the PlayerList packet. It represents a single player using the UUID
// found in the entry, and contains several properties such as the skin.
type PlayerListEntry struct {
// UUID is the UUID of the player as sent in the Login packet when the client joined the server. It must
// match this UUID exactly for the correct XBOX Live icon to show up in the list.
UUID uuid.UUID
// EntityUniqueID is the unique entity ID of the player. This ID typically stays consistent during the
// lifetime of a world, but servers often send the runtime ID for this.
EntityUniqueID int64
// Username is the username that is shown in the player list of the player that obtains a PlayerList
// packet with this entry. It does not have to be the same as the actual username of the player.
Username string
// XUID is the XBOX Live user ID of the player, which will remain consistent as long as the player is
// logged in with the XBOX Live account.
XUID string
// PlatformChatID is an identifier only set for particular platforms when chatting (presumably only for
// Nintendo Switch). It is otherwise an empty string, and is used to decide which players are able to
// chat with each other.
PlatformChatID string
// BuildPlatform is the platform of the player as sent by that player in the Login packet.
BuildPlatform int32
// Skin is the skin of the player that should be added to the player list. Once sent here, it will not
// have to be sent again.
Skin protocol.Skin
// Teacher is a Minecraft: Education Edition field. It specifies if the player to be added to the player
// list is a teacher.
Teacher bool
// Host specifies if the player that is added to the player list is the host of the game.
Host bool
// SubClient specifies if the player that is added to the player list is a sub-client of another player.
SubClient bool
// PlayerColour is the colour of the player that is shown in UI elements, currently only used for the
// player locator bar.
PlayerColour int32
}
// Marshal encodes/decodes a PlayerListEntry.
func (x *PlayerListEntry) Marshal(r protocol.IO) {
r.UUID(&x.UUID)
r.Varint64(&x.EntityUniqueID)
r.String(&x.Username)
r.String(&x.XUID)
r.String(&x.PlatformChatID)
r.Int32(&x.BuildPlatform)
protocol.Single(r, &x.Skin)
r.Bool(&x.Teacher)
r.Bool(&x.Host)
r.Bool(&x.SubClient)
if IsProtoGTE(r, ID800) {
r.Int32(&x.PlayerColour)
}
}
// FromLatest ...
func (x *PlayerListEntry) FromLatest(y protocol.PlayerListEntry) PlayerListEntry {
x.UUID = y.UUID
x.EntityUniqueID = y.EntityUniqueID
x.Username = y.Username
x.XUID = y.XUID
x.PlatformChatID = y.PlatformChatID
x.BuildPlatform = y.BuildPlatform
x.Skin = y.Skin
x.Teacher = y.Teacher
x.Host = y.Host
x.SubClient = y.SubClient
x.PlayerColour = y.PlayerColour
return *x
}
// ToLatest ...
func (x *PlayerListEntry) ToLatest() protocol.PlayerListEntry {
return protocol.PlayerListEntry{
UUID: x.UUID,
EntityUniqueID: x.EntityUniqueID,
Username: x.Username,
XUID: x.XUID,
PlatformChatID: x.PlatformChatID,
BuildPlatform: x.BuildPlatform,
Skin: x.Skin,
Teacher: x.Teacher,
Host: x.Host,
SubClient: x.SubClient,
PlayerColour: x.PlayerColour,
}
}
// PlayerListRemoveEntry encodes/decodes a PlayerListEntry for removal from the list.
func PlayerListRemoveEntry(r protocol.IO, x *PlayerListEntry) {
r.UUID(&x.UUID)
}

View File

@@ -120,6 +120,10 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
return func() packet.Packet { return &legacypacket.UpdatePlayerGameType{} }
case packet.IDSetActorMotion:
return func() packet.Packet { return &legacypacket.SetActorMotion{} }
case packet.IDBiomeDefinitionList:
return func() packet.Packet { return &legacypacket.BiomeDefinitionList{} }
case packet.IDPlayerList:
return func() packet.Packet { return &legacypacket.PlayerList{} }
default:
return cur
}
@@ -708,6 +712,20 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
Elements: pk.Elements,
Visibility: pk.Visibility,
}
case *packet.BiomeDefinitionList:
pks[pkIndex] = &legacypacket.BiomeDefinitionList{
BiomeDefinitions: pk.BiomeDefinitions,
StringList: pk.StringList,
}
case *packet.PlayerList:
entries := make([]proto.PlayerListEntry, len(pk.Entries))
for i, e := range pk.Entries {
entries[i] = (&proto.PlayerListEntry{}).FromLatest(e)
}
pks[pkIndex] = &legacypacket.PlayerList{
ActionType: pk.ActionType,
Entries: entries,
}
}
}
@@ -1213,6 +1231,20 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
Elements: pk.Elements,
Visibility: pk.Visibility,
}
case *legacypacket.BiomeDefinitionList:
pks[pkIndex] = &packet.BiomeDefinitionList{
BiomeDefinitions: pk.BiomeDefinitions,
StringList: pk.StringList,
}
case *legacypacket.PlayerList:
entries := make([]protocol.PlayerListEntry, len(pk.Entries))
for i, e := range pk.Entries {
entries[i] = e.ToLatest()
}
pks[pkIndex] = &packet.PlayerList{
ActionType: pk.ActionType,
Entries: entries,
}
}
}
return pks

View File

@@ -2,6 +2,8 @@ package legacyver
import (
_ "embed"
"github.com/akmalfairuz/legacy-version/internal/chunk"
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/akmalfairuz/legacy-version/mapping"
)
@@ -18,6 +20,15 @@ var (
//go:embed data/block_states_786.nbt
blockStateData786 []byte
itemMappingLatest = mapping.NewItemMapping(requiredItemList786, ItemVersion786)
blockMappingLatest = mapping.NewBlockMapping(blockStateData786)
itemMapping786 = mapping.NewItemMapping(requiredItemList786, ItemVersion786)
blockMapping786 = mapping.NewBlockMapping(blockStateData786)
)
func New786() *Protocol {
return &Protocol{
ver: "1.21.70",
id: proto.ID786,
blockTranslator: NewBlockTranslator(blockMapping786, blockMappingLatest, chunk.NewNetworkPersistentEncoding(blockMapping786, BlockVersion786), chunk.NewBlockPaletteEncoding(blockMapping786, BlockVersion786), false),
itemTranslator: NewItemTranslator(itemMapping786, itemMappingLatest, blockMapping786, blockMappingLatest),
}
}

23
legacyver/v800.go Normal file
View File

@@ -0,0 +1,23 @@
package legacyver
import (
_ "embed"
"github.com/akmalfairuz/legacy-version/mapping"
)
const (
// ItemVersion800 ...
ItemVersion800 = 251
// BlockVersion800 ...
BlockVersion800 int32 = (1 << 24) | (21 << 16) | (80 << 8)
)
var (
//go:embed data/required_item_list_800.json
requiredItemList800 []byte
//go:embed data/block_states_800.nbt
blockStateData800 []byte
itemMappingLatest = mapping.NewItemMapping(requiredItemList800, ItemVersion800)
blockMappingLatest = mapping.NewBlockMapping(blockStateData800)
)