Update legacy protocol support to v1.21.90

This commit is contained in:
AkmalFairuz
2025-06-18 23:54:54 +07:00
parent 8a209b75bf
commit fd5e43eea7
13 changed files with 9376 additions and 9 deletions

View File

@@ -1,10 +1,13 @@
package legacyver
import "github.com/sandertv/gophertunnel/minecraft"
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{
New800(),
New786(),
New776(),
New766(),

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -20,6 +20,9 @@ type ResourcePacksInfo struct {
// HasScripts specifies if any of the resource packs contain scripts in them. If set to true, only clients
// that support scripts will be able to download them.
HasScripts bool
// ForceDisableVibrantVisuals specifies if the vibrant visuals feature should be forcibly disabled on the server.Add commentMore actions
// If set to true, the server will ensure that vibrant visuals are not enabled, regardless of the client's settings.
ForceDisableVibrantVisuals bool
// WorldTemplateUUID is the UUID of the template that has been used to generate the world. Templates can
// be downloaded from the marketplace or installed via '.mctemplate' files. If the world was not generated
// from a template, this field is empty.
@@ -52,6 +55,9 @@ func (pk *ResourcePacksInfo) Marshal(io protocol.IO) {
}
io.Bool(&pk.HasScripts)
if proto.IsProtoGTE(io, proto.ID766) {
if proto.IsProtoGTE(io, proto.ID818) {
io.Bool(&pk.ForceDisableVibrantVisuals)
}
io.UUID(&pk.WorldTemplateUUID)
io.String(&pk.WorldTemplateVersion)
}

View File

@@ -232,6 +232,8 @@ type StartGame struct {
WorldID string
// ScenarioID is always empty in vanilla and its usage is currently unknown.
ScenarioID string
// OwnerID is always empty in vanilla and its usage is currently unknown.
OwnerID string
// UseBlockNetworkIDHashes is true if the client should use the hash of a block's name as its network ID rather than
// its index in the expected block palette. This is useful for servers that wish to support multiple protocol versions
// and custom blocks, but it will result in extra bytes being written for every block in a sub chunk palette.
@@ -309,6 +311,9 @@ func (pk *StartGame) Marshal(io protocol.IO) {
io.String(&pk.ServerID)
io.String(&pk.WorldID)
io.String(&pk.ScenarioID)
if proto.IsProtoGTE(io, proto.ID818) {
io.String(&pk.OwnerID)
}
}
io.String(&pk.LevelID)
io.String(&pk.WorldName)

View File

@@ -0,0 +1,35 @@
package legacypacket
import (
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
// SubChunk sends data about multiple sub-chunks around a center point.
type SubChunk struct {
// CacheEnabled is whether the sub-chunk caching is enabled or not.
CacheEnabled bool
// 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 []proto.SubChunkEntry
}
// ID ...
func (*SubChunk) ID() uint32 {
return packet.IDSubChunk
}
func (pk *SubChunk) Marshal(io protocol.IO) {
io.Bool(&pk.CacheEnabled)
io.Varint32(&pk.Dimension)
io.SubChunkPos(&pk.Position)
if pk.CacheEnabled {
protocol.SliceUint32Length(io, &pk.SubChunkEntries)
} else {
protocol.FuncIOSliceUint32Length(io, &pk.SubChunkEntries, proto.SubChunkEntryNoCache)
}
}

View File

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

View File

@@ -0,0 +1,93 @@
package proto
import "github.com/sandertv/gophertunnel/minecraft/protocol"
// SubChunkEntry contains the data of a sub-chunk entry relative to a center sub chunk position, used for the sub-chunk
// requesting system introduced in v1.18.10.
type SubChunkEntry struct {
// Offset contains the offset between the sub-chunk position and the center position.
Offset protocol.SubChunkOffset
// Result is always one of the constants defined in the SubChunkResult constants.
Result byte
// RawPayload contains the serialized sub-chunk data.
RawPayload []byte
// HeightMapType is always one of the constants defined in the HeightMapData constants.
HeightMapType byte
// HeightMapData is the data for the height map.
HeightMapData []int8
// BlobHash is the hash of the blob.
BlobHash uint64
// RenderHeightMapType is always one of the constants defined in the HeightMapData constants.
RenderHeightMapType byte
// RenderHeightMapData is the data for the render height map.
RenderHeightMapData []int8
// RenderBlobHash is the hash of the render blob.
RenderBlobHash uint64
}
// ToLatest ...
func (x *SubChunkEntry) ToLatest() protocol.SubChunkEntry {
return protocol.SubChunkEntry{
Offset: x.Offset,
Result: x.Result,
RawPayload: x.RawPayload,
HeightMapType: x.HeightMapType,
HeightMapData: x.HeightMapData,
BlobHash: x.BlobHash,
RenderHeightMapType: x.RenderHeightMapType,
RenderHeightMapData: x.RenderHeightMapData,
RenderBlobHash: x.RenderBlobHash,
}
}
// FromLatest converts a protocol.SubChunkEntry to a SubChunkEntry. It is used to convert the latest
func (x *SubChunkEntry) FromLatest(y protocol.SubChunkEntry) SubChunkEntry {
x.Offset = y.Offset
x.Result = y.Result
x.RawPayload = y.RawPayload
x.HeightMapType = y.HeightMapType
x.HeightMapData = y.HeightMapData
x.BlobHash = y.BlobHash
x.RenderHeightMapType = y.RenderHeightMapType
x.RenderHeightMapData = y.RenderHeightMapData
x.RenderBlobHash = y.RenderBlobHash
return *x
}
// Marshal encodes/decodes a SubChunkEntry assuming the blob cache is enabled.
func (x *SubChunkEntry) Marshal(r protocol.IO) {
protocol.Single(r, &x.Offset)
r.Uint8(&x.Result)
if x.Result != protocol.SubChunkResultSuccessAllAir {
r.ByteSlice(&x.RawPayload)
}
r.Uint8(&x.HeightMapType)
if x.HeightMapType == protocol.HeightMapDataHasData {
protocol.FuncSliceOfLen(r, 256, &x.HeightMapData, r.Int8)
}
r.Uint64(&x.BlobHash)
if IsProtoGTE(r, ID818) {
r.Uint8(&x.RenderHeightMapType)
if x.RenderHeightMapType == protocol.HeightMapDataHasData {
protocol.FuncSliceOfLen(r, 256, &x.RenderHeightMapData, r.Int8)
}
r.Uint64(&x.RenderBlobHash)
}
}
// SubChunkEntryNoCache encodes/decodes a SubChunkEntry assuming the blob cache is not enabled.
func SubChunkEntryNoCache(r protocol.IO, x *SubChunkEntry) {
protocol.Single(r, &x.Offset)
r.Uint8(&x.Result)
r.ByteSlice(&x.RawPayload)
r.Uint8(&x.HeightMapType)
if IsProtoGTE(r, ID818) {
if x.HeightMapType == protocol.HeightMapDataHasData {
protocol.FuncSliceOfLen(r, 256, &x.HeightMapData, r.Int8)
}
r.Uint8(&x.RenderHeightMapType)
if x.RenderHeightMapType == protocol.HeightMapDataHasData {
protocol.FuncSliceOfLen(r, 256, &x.RenderHeightMapData, r.Int8)
}
}
}

View File

@@ -124,6 +124,8 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
return func() packet.Packet { return &legacypacket.BiomeDefinitionList{} }
case packet.IDPlayerList:
return func() packet.Packet { return &legacypacket.PlayerList{} }
case packet.IDSubChunk:
return func() packet.Packet { return &legacypacket.SubChunk{} }
default:
return cur
}
@@ -726,6 +728,17 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
ActionType: pk.ActionType,
Entries: entries,
}
case *packet.SubChunk:
entries := make([]proto.SubChunkEntry, len(pk.SubChunkEntries))
for i, e := range pk.SubChunkEntries {
entries[i] = (&proto.SubChunkEntry{}).FromLatest(e)
}
pks[pkIndex] = &legacypacket.SubChunk{
CacheEnabled: pk.CacheEnabled,
Dimension: pk.Dimension,
Position: pk.Position,
SubChunkEntries: entries,
}
}
}
@@ -1203,7 +1216,7 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
pks[pkIndex] = &packet.UpdateAbilities{AbilityData: pk.AbilityData.ToLatest()}
case *legacypacket.ClientMovementPredictionSync:
pks[pkIndex] = &packet.ClientMovementPredictionSync{
ActorFlags: fitBitset(pk.ActorFlags, packet.ClientMovementPredictionSyncBitsetSize),
ActorFlags: fitBitset(pk.ActorFlags, protocol.EntityDataFlagCount),
BoundingBoxScale: pk.BoundingBoxScale,
BoundingBoxWidth: pk.BoundingBoxWidth,
BoundingBoxHeight: pk.BoundingBoxHeight,
@@ -1245,6 +1258,17 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
ActionType: pk.ActionType,
Entries: entries,
}
case *legacypacket.SubChunk:
entries := make([]protocol.SubChunkEntry, len(pk.SubChunkEntries))
for i, e := range pk.SubChunkEntries {
entries[i] = e.ToLatest()
}
pks[pkIndex] = &packet.SubChunk{
CacheEnabled: pk.CacheEnabled,
Dimension: pk.Dimension,
Position: pk.Position,
SubChunkEntries: 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_800.nbt
blockStateData800 []byte
itemMappingLatest = mapping.NewItemMapping(requiredItemList800, ItemVersion800)
blockMappingLatest = mapping.NewBlockMapping(blockStateData800)
itemMapping800 = mapping.NewItemMapping(requiredItemList800, ItemVersion800)
blockMapping800 = mapping.NewBlockMapping(blockStateData800)
)
func New800() *Protocol {
return &Protocol{
ver: "1.21.80",
id: proto.ID800,
blockTranslator: NewBlockTranslator(blockMapping800, blockMappingLatest, chunk.NewNetworkPersistentEncoding(blockMapping800, BlockVersion800), chunk.NewBlockPaletteEncoding(blockMapping800, BlockVersion800), false),
itemTranslator: NewItemTranslator(itemMapping800, itemMappingLatest, blockMapping800, blockMappingLatest),
}
}

23
legacyver/v818.go Normal file
View File

@@ -0,0 +1,23 @@
package legacyver
import (
_ "embed"
"github.com/akmalfairuz/legacy-version/mapping"
)
const (
// ItemVersion818 ...
ItemVersion818 = 261
// BlockVersion818 ...
BlockVersion818 int32 = (1 << 24) | (21 << 16) | (90 << 8)
)
var (
//go:embed data/required_item_list_818.json
requiredItemList818 []byte
//go:embed data/block_states_818.nbt
blockStateData818 []byte
itemMappingLatest = mapping.NewItemMapping(requiredItemList818, ItemVersion818)
blockMappingLatest = mapping.NewBlockMapping(blockStateData818)
)