Add 1.21.20

This commit is contained in:
AkmalFairuz
2025-01-01 12:34:03 +07:00
parent 93821ab4c6
commit 9677eef999
19 changed files with 7267 additions and 60 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,24 @@
package legacypacket
import (
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
// ContainerRegistryCleanup is sent by the server to trigger a client-side cleanup of the dynamic container
// registry.
type ContainerRegistryCleanup struct {
// RemovedContainers is a list of protocol.FullContainerName's that should be removed from the client-side
// container registry.
RemovedContainers []proto.FullContainerName
}
// ID ...
func (*ContainerRegistryCleanup) ID() uint32 {
return packet.IDContainerRegistryCleanup
}
func (pk *ContainerRegistryCleanup) Marshal(io protocol.IO) {
protocol.Slice(io, &pk.RemovedContainers)
}

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 (
EmoteFlagServerSide = 1 << iota
EmoteFlagMuteChat
)
// Emote is sent by both the server and the client. When the client sends an emote, it sends this packet to
// the server, after which the server will broadcast the packet to other players online.
type Emote struct {
// EntityRuntimeID is the entity that sent the emote. When a player sends this packet, it has this field
// set as its own entity runtime ID.
EntityRuntimeID uint64
// EmoteLength is the number of ticks that the emote lasts for.
EmoteLength uint32
// EmoteID is the ID of the emote to send.
EmoteID string
// XUID is the Xbox User ID of the player that sent the emote. It is only set when the emote is used by a player that
// is authenticated with Xbox Live.
XUID string
// PlatformID is an identifier only set for particular platforms when using an emote (presumably only for Nintendo
// Switch). It is otherwise an empty string, and is used to decide which players are able to emote with each other.
PlatformID string
// Flags is a combination of flags that change the way the Emote packet operates. When the server sends
// this packet to other players, EmoteFlagServerSide must be present.
Flags byte
}
// ID ...
func (*Emote) ID() uint32 {
return packet.IDEmote
}
func (pk *Emote) Marshal(io protocol.IO) {
io.Varuint64(&pk.EntityRuntimeID)
io.String(&pk.EmoteID)
if proto.IsProtoGTE(io, proto.ID729) {
io.Varuint32(&pk.EmoteLength)
}
io.String(&pk.XUID)
io.String(&pk.PlatformID)
io.Uint8(&pk.Flags)
}

View File

@@ -17,7 +17,7 @@ type InventoryContent struct {
// the inventory window updated.
Content []protocol.ItemInstance
// Container is the protocol.FullContainerName that describes the container that the content is for.
Container protocol.FullContainerName
Container proto.FullContainerName
// DynamicContainerSize ...
DynamicContainerSize uint32
// StorageItem is the item that is acting as the storage container for the inventory. If the inventory is
@@ -34,7 +34,9 @@ func (*InventoryContent) ID() uint32 {
func (pk *InventoryContent) Marshal(io protocol.IO) {
io.Varuint32(&pk.WindowID)
protocol.FuncSlice(io, &pk.Content, io.ItemInstance)
protocol.Single(io, &pk.Container)
if proto.IsProtoGTE(io, proto.ID729) {
protocol.Single(io, &pk.Container)
}
if proto.IsProtoGTE(io, proto.ID748) {
io.ItemInstance(&pk.StorageItem)
} else {

View File

@@ -17,7 +17,7 @@ type InventorySlot struct {
// index.
Slot uint32
// Container is the protocol.FullContainerName that describes the container that the content is for.
Container protocol.FullContainerName
Container proto.FullContainerName
// DynamicContainerSize ...
DynamicContainerSize uint32
// StorageItem is the item that is acting as the storage container for the inventory. If the inventory is
@@ -37,7 +37,9 @@ func (*InventorySlot) ID() uint32 {
func (pk *InventorySlot) Marshal(io protocol.IO) {
io.Varuint32(&pk.WindowID)
io.Varuint32(&pk.Slot)
protocol.Single(io, &pk.Container)
if proto.IsProtoGTE(io, proto.ID729) {
protocol.Single(io, &pk.Container)
}
if proto.IsProtoGTE(io, proto.ID748) {
io.ItemInstance(&pk.StorageItem)
} else {

View File

@@ -27,6 +27,10 @@ type ResourcePacksInfo struct {
// WorldTemplateVersion is the version of the world template that has been used to generate the world. If
// the world was not generated from a template, this field is empty.
WorldTemplateVersion string
// ForcingServerPacks ...
ForcingServerPacks bool
// BehaviourPacks ...
BehaviourPacks []proto.BehaviourPackInfo
// TexturePacks is a list of texture packs that the client needs to download before joining the server.
// The order of these texture packs is not relevant in this packet. It is however important in the
// ResourcePackStack packet.
@@ -49,6 +53,12 @@ func (pk *ResourcePacksInfo) Marshal(io protocol.IO) {
io.UUID(&pk.WorldTemplateUUID)
io.String(&pk.WorldTemplateVersion)
}
if proto.IsProtoLT(io, proto.ID729) {
io.Bool(&pk.ForcingServerPacks)
protocol.SliceUint16Length(io, &pk.BehaviourPacks)
} else {
proto.EmptySlice(io, &pk.BehaviourPacks)
}
protocol.SliceUint16Length(io, &pk.TexturePacks)
if proto.IsProtoLT(io, proto.ID748) {
protocol.Slice(io, &pk.PackURLs)

View File

@@ -0,0 +1,31 @@
package legacypacket
import (
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
// Transfer is sent by the server to transfer a player from the current server to another. Doing so will
// fully disconnect the client, bring it back to the main menu and make it connect to the next server.
type Transfer struct {
// Address is the address of the new server, which might be either a hostname or an actual IP address.
Address string
// Port is the UDP port of the new server.
Port uint16
// ReloadWorld currently has an unknown usage.
ReloadWorld bool
}
// ID ...
func (*Transfer) ID() uint32 {
return packet.IDTransfer
}
func (pk *Transfer) Marshal(io protocol.IO) {
io.String(&pk.Address)
io.Uint16(&pk.Port)
if proto.IsProtoGTE(io, proto.ID729) {
io.Bool(&pk.ReloadWorld)
}
}

View File

@@ -0,0 +1,32 @@
package legacypacket
import (
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
// UpdateAttributes is sent by the server to update an amount of attributes of any entity in the world. These
// attributes include ones such as the health or the movement speed of the entity.
type UpdateAttributes struct {
// EntityRuntimeID is the runtime ID of the entity. The runtime ID is unique for each world session, and
// entities are generally identified in packets using this runtime ID.
EntityRuntimeID uint64
// Attributes is a slice of new attributes that the entity gets. It includes attributes such as its
// health, movement speed, etc. Note that only changed attributes have to be sent in this packet. It is
// not required to send attributes that did not have their values changed.
Attributes []proto.Attribute
// Tick is the server tick at which the packet was sent. It is used in relation to CorrectPlayerMovePrediction.
Tick uint64
}
// ID ...
func (*UpdateAttributes) ID() uint32 {
return packet.IDUpdateAttributes
}
func (pk *UpdateAttributes) Marshal(io protocol.IO) {
io.Varuint64(&pk.EntityRuntimeID)
protocol.Slice(io, &pk.Attributes)
io.Varuint64(&pk.Tick)
}

View File

@@ -0,0 +1,58 @@
package proto
import "github.com/sandertv/gophertunnel/minecraft/protocol"
// Attribute is an entity attribute, that holds specific data such as the health of the entity. Each attribute
// holds a default value, maximum and minimum value, name and its current value.
type Attribute struct {
protocol.AttributeValue
// DefaultMin is the default minimum value of the attribute. It's not clear why this field must be sent to
// the client, but it is required regardless.
DefaultMin float32
// DefaultMax is the default maximum value of the attribute. It's not clear why this field must be sent to
// the client, but it is required regardless.
DefaultMax float32
// Default is the default value of the attribute. It's not clear why this field must be sent to the
// client, but it is required regardless.
Default float32
// Modifiers is a slice of AttributeModifiers that are applied to the attribute.
Modifiers []protocol.AttributeModifier
}
func (x *Attribute) FromLatest(v protocol.Attribute) Attribute {
x.AttributeValue = v.AttributeValue
x.DefaultMin = v.DefaultMin
x.DefaultMax = v.DefaultMax
x.Default = v.Default
x.Modifiers = v.Modifiers
return *x
}
func (x *Attribute) ToLatest() protocol.Attribute {
return protocol.Attribute{
AttributeValue: protocol.AttributeValue{
Name: x.Name,
Value: x.Value,
Max: x.Max,
Min: x.Min,
},
DefaultMin: x.DefaultMin,
DefaultMax: x.DefaultMax,
Default: x.Default,
Modifiers: x.Modifiers,
}
}
// Marshal encodes/decodes an Attribute.
func (x *Attribute) Marshal(r protocol.IO) {
r.Float32(&x.Min)
r.Float32(&x.Max)
r.Float32(&x.Value)
if IsProtoGTE(r, ID729) {
r.Float32(&x.DefaultMin)
r.Float32(&x.DefaultMax)
}
r.Float32(&x.Default)
r.String(&x.Name)
protocol.Slice(r, &x.Modifiers)
}

View File

@@ -53,7 +53,7 @@ type CameraPreset struct {
AimAssist protocol.Optional[protocol.CameraPresetAimAssist]
}
func (x *CameraPreset) FromLatest(cp protocol.CameraPreset) {
func (x *CameraPreset) FromLatest(cp protocol.CameraPreset) CameraPreset {
x.Name = cp.Name
x.Parent = cp.Parent
x.PosX = cp.PosX
@@ -74,6 +74,7 @@ func (x *CameraPreset) FromLatest(cp protocol.CameraPreset) {
x.PlayerEffects = cp.PlayerEffects
x.AlignTargetAndCameraForward = cp.AlignTargetAndCameraForward
x.AimAssist = cp.AimAssist
return *x
}
func (x *CameraPreset) ToLatest() protocol.CameraPreset {
@@ -110,8 +111,10 @@ func (x *CameraPreset) Marshal(r protocol.IO) {
protocol.OptionalFunc(r, &x.PosZ, r.Float32)
protocol.OptionalFunc(r, &x.RotX, r.Float32)
protocol.OptionalFunc(r, &x.RotY, r.Float32)
protocol.OptionalFunc(r, &x.RotationSpeed, r.Float32)
protocol.OptionalFunc(r, &x.SnapToTarget, r.Bool)
if IsProtoGTE(r, ID729) {
protocol.OptionalFunc(r, &x.RotationSpeed, r.Float32)
protocol.OptionalFunc(r, &x.SnapToTarget, r.Bool)
}
if IsProtoGTE(r, ID748) {
protocol.OptionalFunc(r, &x.HorizontalRotationLimit, r.Vec2)
protocol.OptionalFunc(r, &x.VerticalRotationLimit, r.Vec2)
@@ -121,7 +124,9 @@ func (x *CameraPreset) Marshal(r protocol.IO) {
protocol.OptionalFunc(r, &x.TrackingRadius, r.Float32)
}
protocol.OptionalFunc(r, &x.ViewOffset, r.Vec2)
protocol.OptionalFunc(r, &x.EntityOffset, r.Vec3)
if IsProtoGTE(r, ID729) {
protocol.OptionalFunc(r, &x.EntityOffset, r.Vec3)
}
protocol.OptionalFunc(r, &x.Radius, r.Float32)
protocol.OptionalFunc(r, &x.AudioListener, r.Uint8)
protocol.OptionalFunc(r, &x.PlayerEffects, r.Bool)

View File

@@ -0,0 +1,38 @@
package proto
import "github.com/sandertv/gophertunnel/minecraft/protocol"
// FullContainerName contains information required to identify a container in a StackRequestSlotInfo.
type FullContainerName struct {
// ContainerID is the ID of the container that the slot was in.
ContainerID byte
// DynamicContainerID is the ID of the container if it is dynamic. If the container is not dynamic, this
// field should be left empty. A non-optional value of 0 is assumed to be non-empty.
DynamicContainerID protocol.Optional[uint32]
}
func (x *FullContainerName) FromLatest(v protocol.FullContainerName) FullContainerName {
x.ContainerID = v.ContainerID
x.DynamicContainerID = v.DynamicContainerID
return *x
}
func (x *FullContainerName) ToLatest() protocol.FullContainerName {
return protocol.FullContainerName{
ContainerID: x.ContainerID,
DynamicContainerID: x.DynamicContainerID,
}
}
func (x *FullContainerName) Marshal(r protocol.IO) {
r.Uint8(&x.ContainerID)
if IsProtoGTE(r, ID729) {
protocol.OptionalFunc(r, &x.DynamicContainerID, r.Uint32)
} else {
dynamicContainerID, _ := x.DynamicContainerID.Value()
r.Uint32(&dynamicContainerID)
if dynamicContainerID != 0 {
x.DynamicContainerID = protocol.Option(dynamicContainerID)
}
}
}

View File

@@ -3,12 +3,12 @@ package proto
import "github.com/sandertv/gophertunnel/minecraft/protocol"
const (
ID766 = 766
ID748 = 748
ID729 = 729
ID712 = 712
ID686 = 686
ID685 = 685
ID766 = 766 // v1.21.50
ID748 = 748 // v1.21.40
ID729 = 729 // v1.21.30
ID712 = 712 // v1.21.20
ID686 = 686 // v1.21.2
ID685 = 685 // v1.21.0
)
func IsProtoGTE(io protocol.IO, proto int32) bool {

View File

@@ -226,6 +226,32 @@ type ItemStackResponse struct {
ContainerInfo []StackResponseContainerInfo
}
func (x *ItemStackResponse) FromLatest(y protocol.ItemStackResponse) ItemStackResponse {
ret := ItemStackResponse{
Status: y.Status,
RequestID: y.RequestID,
ContainerInfo: make([]StackResponseContainerInfo, len(y.ContainerInfo)),
}
for i, v := range y.ContainerInfo {
ret.ContainerInfo[i] = StackResponseContainerInfo{
Container: (&FullContainerName{}).FromLatest(v.Container),
SlotInfo: make([]StackResponseSlotInfo, len(v.SlotInfo)),
}
for j, w := range v.SlotInfo {
ret.ContainerInfo[i].SlotInfo[j] = StackResponseSlotInfo{
Slot: w.Slot,
HotbarSlot: w.HotbarSlot,
Count: w.Count,
StackNetworkID: w.StackNetworkID,
CustomName: w.CustomName,
FilteredCustomName: w.FilteredCustomName,
DurabilityCorrection: w.DurabilityCorrection,
}
}
}
return ret
}
func (x *ItemStackResponse) ToLatest() protocol.ItemStackResponse {
ret := protocol.ItemStackResponse{
Status: x.Status,
@@ -234,7 +260,7 @@ func (x *ItemStackResponse) ToLatest() protocol.ItemStackResponse {
}
for i, v := range x.ContainerInfo {
ret.ContainerInfo[i] = protocol.StackResponseContainerInfo{
Container: v.Container,
Container: v.Container.ToLatest(),
SlotInfo: make([]protocol.StackResponseSlotInfo, len(v.SlotInfo)),
}
for j, w := range v.SlotInfo {
@@ -266,7 +292,7 @@ type StackResponseContainerInfo struct {
// Container is the FullContainerName that describes the container that the slots that follow are in. For
// the main inventory, the ContainerID seems to be 0x1b. Fur the cursor, this value seems to be 0x3a. For
// the crafting grid, this value seems to be 0x0d.
Container protocol.FullContainerName
Container FullContainerName
// SlotInfo holds information on what item stack should be present in specific slots in the container.
SlotInfo []StackResponseSlotInfo
}
@@ -635,7 +661,7 @@ func (a *CraftResultsDeprecatedStackRequestAction) Marshal(r protocol.IO) {
// StackRequestSlotInfo holds information on a specific slot client-side.
type StackRequestSlotInfo struct {
// Container is the FullContainerName that describes the container that the slot is in.
Container protocol.FullContainerName
Container FullContainerName
// Slot is the index of the slot within the container with the ContainerID above.
Slot byte
// StackNetworkID is the unique stack ID that the client assumes to be present in this slot. The server

View File

@@ -38,6 +38,20 @@ type TexturePackInfo struct {
DownloadURL string
}
func (x *TexturePackInfo) FromLatest(y protocol.TexturePackInfo) TexturePackInfo {
x.UUID = y.UUID
x.Version = y.Version
x.Size = y.Size
x.ContentKey = y.ContentKey
x.SubPackName = y.SubPackName
x.ContentIdentity = y.ContentIdentity
x.HasScripts = y.HasScripts
x.AddonPack = y.AddonPack
x.RTXEnabled = y.RTXEnabled
x.DownloadURL = y.DownloadURL
return *x
}
func (x *TexturePackInfo) ToLatest() protocol.TexturePackInfo {
return protocol.TexturePackInfo{
UUID: x.UUID,
@@ -79,3 +93,42 @@ func (x *TexturePackInfo) Marshal(r protocol.IO) {
r.String(&x.DownloadURL)
}
}
// BehaviourPackInfo represents a behaviour pack's info sent over network. It holds information about the
// behaviour pack such as its name, description and version.
type BehaviourPackInfo struct {
// UUID is the UUID of the behaviour pack. Each behaviour pack downloaded must have a different UUID in
// order for the client to be able to handle them properly.
UUID string
// Version is the version of the behaviour pack. The client will cache behaviour packs sent by the server as
// long as they carry the same version. Sending a behaviour pack with a different version than previously
// will force the client to re-download it.
Version string
// Size is the total size in bytes that the behaviour pack occupies. This is the size of the compressed
// archive (zip) of the behaviour pack.
Size uint64
// ContentKey is the key used to decrypt the behaviour pack if it is encrypted. This is generally the case
// for marketplace behaviour packs.
ContentKey string
// SubPackName ...
SubPackName string
// ContentIdentity ...
ContentIdentity string
// HasScripts specifies if the behaviour packs has any scripts in it. A client will only download the
// behaviour pack if it supports scripts, which, up to 1.11, only includes Windows 10.
HasScripts bool
// AddonPack specifies if the texture pack is from an addon.
AddonPack bool
}
// Marshal encodes/decodes a BehaviourPackInfo.
func (x *BehaviourPackInfo) Marshal(r protocol.IO) {
r.String(&x.UUID)
r.String(&x.Version)
r.Uint64(&x.Size)
r.String(&x.ContentKey)
r.String(&x.SubPackName)
r.String(&x.ContentIdentity)
r.Bool(&x.HasScripts)
r.Bool(&x.AddonPack)
}

View File

@@ -28,6 +28,10 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
return func() packet.Packet { return &legacypacket.CameraAimAssist{} }
case packet.IDCameraPresets:
return func() packet.Packet { return &legacypacket.CameraPresets{} }
case packet.IDContainerRegistryCleanup:
return func() packet.Packet { return &legacypacket.ContainerRegistryCleanup{} }
case packet.IDEmote:
return func() packet.Packet { return &legacypacket.Emote{} }
case packet.IDInventoryContent:
return func() packet.Packet { return &legacypacket.InventoryContent{} }
case packet.IDInventorySlot:
@@ -40,6 +44,10 @@ func convertPacketFunc(pid uint32, cur func() packet.Packet) func() packet.Packe
return func() packet.Packet { return &legacypacket.PlayerAuthInput{} }
case packet.IDResourcePacksInfo:
return func() packet.Packet { return &legacypacket.ResourcePacksInfo{} }
case packet.IDTransfer:
return func() packet.Packet { return &legacypacket.Transfer{} }
case packet.IDUpdateAttributes:
return func() packet.Packet { return &legacypacket.UpdateAttributes{} }
default:
return cur
}
@@ -94,7 +102,7 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
case *packet.CameraPresets:
presets := make([]proto.CameraPreset, len(pk.Presets))
for i, p := range pk.Presets {
presets[i].FromLatest(p)
presets[i] = (&proto.CameraPreset{}).FromLatest(p)
}
pks[pkIndex] = &legacypacket.CameraPresets{
Presets: presets,
@@ -133,49 +141,14 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
case *packet.ItemStackResponse:
responses := make([]proto.ItemStackResponse, len(pk.Responses))
for i, r := range pk.Responses {
containerInfo := make([]proto.StackResponseContainerInfo, len(r.ContainerInfo))
for j, c := range r.ContainerInfo {
slotInfo := make([]proto.StackResponseSlotInfo, len(c.SlotInfo))
for k, s := range c.SlotInfo {
slotInfo[k] = proto.StackResponseSlotInfo{
Slot: s.Slot,
HotbarSlot: s.HotbarSlot,
Count: s.Count,
StackNetworkID: s.StackNetworkID,
CustomName: s.CustomName,
FilteredCustomName: s.FilteredCustomName,
DurabilityCorrection: s.DurabilityCorrection,
}
}
containerInfo[j] = proto.StackResponseContainerInfo{
Container: c.Container,
SlotInfo: slotInfo,
}
}
responses[i] = proto.ItemStackResponse{
Status: r.Status,
RequestID: r.RequestID,
ContainerInfo: containerInfo,
}
responses[i] = (&proto.ItemStackResponse{}).FromLatest(r)
}
pks[pkIndex] = &legacypacket.ItemStackResponse{Responses: responses}
case *packet.ResourcePacksInfo:
texturePacks := make([]proto.TexturePackInfo, len(pk.TexturePacks))
packURLs := make([]protocol.PackURL, 0)
for i, t := range pk.TexturePacks {
texturePacks[i] = proto.TexturePackInfo{
UUID: t.UUID,
Version: t.Version,
Size: t.Size,
ContentKey: t.ContentKey,
SubPackName: t.SubPackName,
ContentIdentity: t.ContentIdentity,
HasScripts: t.HasScripts,
AddonPack: t.AddonPack,
RTXEnabled: t.RTXEnabled,
DownloadURL: t.DownloadURL,
}
texturePacks[i] = (&proto.TexturePackInfo{}).FromLatest(t)
if t.DownloadURL != "" {
packURLs = append(packURLs, protocol.PackURL{
UUIDVersion: t.UUID.String() + "_" + t.Version,
@@ -196,7 +169,7 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
pks[pkIndex] = &legacypacket.InventorySlot{
WindowID: pk.WindowID,
Slot: pk.Slot,
Container: pk.Container,
Container: (&proto.FullContainerName{}).FromLatest(pk.Container),
DynamicContainerSize: 0,
StorageItem: pk.StorageItem,
NewItem: pk.NewItem,
@@ -205,7 +178,7 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
pks[pkIndex] = &legacypacket.InventoryContent{
WindowID: pk.WindowID,
Content: pk.Content,
Container: pk.Container,
Container: (&proto.FullContainerName{}).FromLatest(pk.Container),
DynamicContainerSize: 0,
StorageItem: pk.StorageItem,
}
@@ -227,6 +200,39 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
TargetMode: pk.TargetMode,
Action: pk.Action,
}
case *packet.UpdateAttributes:
attributes := make([]proto.Attribute, len(pk.Attributes))
for i, a := range pk.Attributes {
attributes[i] = (&proto.Attribute{}).FromLatest(a)
}
pks[pkIndex] = &legacypacket.UpdateAttributes{
EntityRuntimeID: pk.EntityRuntimeID,
Attributes: attributes,
Tick: pk.Tick,
}
case *packet.ContainerRegistryCleanup:
removedContainers := make([]proto.FullContainerName, len(pk.RemovedContainers))
for i, c := range pk.RemovedContainers {
removedContainers[i] = (&proto.FullContainerName{}).FromLatest(c)
}
pks[pkIndex] = &legacypacket.ContainerRegistryCleanup{
RemovedContainers: removedContainers,
}
case *packet.Emote:
pks[pkIndex] = &legacypacket.Emote{
EntityRuntimeID: pk.EntityRuntimeID,
EmoteLength: pk.EmoteLength,
EmoteID: pk.EmoteID,
XUID: pk.XUID,
PlatformID: pk.PlatformID,
Flags: pk.Flags,
}
case *packet.Transfer:
pks[pkIndex] = &legacypacket.Transfer{
Address: pk.Address,
Port: pk.Port,
ReloadWorld: pk.ReloadWorld,
}
}
}
@@ -304,7 +310,7 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
pks[pkIndex] = &packet.InventorySlot{
WindowID: pk.WindowID,
Slot: pk.Slot,
Container: pk.Container,
Container: pk.Container.ToLatest(),
StorageItem: pk.StorageItem,
NewItem: pk.NewItem,
}
@@ -312,7 +318,7 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
pks[pkIndex] = &packet.InventoryContent{
WindowID: pk.WindowID,
Content: pk.Content,
Container: pk.Container,
Container: pk.Container.ToLatest(),
StorageItem: pk.StorageItem,
}
case *legacypacket.MobEffect:
@@ -333,6 +339,39 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
TargetMode: pk.TargetMode,
Action: pk.Action,
}
case *legacypacket.UpdateAttributes:
attributes := make([]protocol.Attribute, len(pk.Attributes))
for i, a := range pk.Attributes {
attributes[i] = a.ToLatest()
}
pks[pkIndex] = &packet.UpdateAttributes{
EntityRuntimeID: pk.EntityRuntimeID,
Attributes: attributes,
Tick: pk.Tick,
}
case *legacypacket.ContainerRegistryCleanup:
removedContainers := make([]protocol.FullContainerName, len(pk.RemovedContainers))
for i, c := range pk.RemovedContainers {
removedContainers[i] = c.ToLatest()
}
pks[pkIndex] = &packet.ContainerRegistryCleanup{
RemovedContainers: removedContainers,
}
case *legacypacket.Emote:
pks[pkIndex] = &packet.Emote{
EntityRuntimeID: pk.EntityRuntimeID,
EmoteLength: pk.EmoteLength,
EmoteID: pk.EmoteID,
XUID: pk.XUID,
PlatformID: pk.PlatformID,
Flags: pk.Flags,
}
case *legacypacket.Transfer:
pks[pkIndex] = &packet.Transfer{
Address: pk.Address,
Port: pk.Port,
ReloadWorld: pk.ReloadWorld,
}
}
}
return pks

36
legacyver/v712.go Normal file
View File

@@ -0,0 +1,36 @@
package legacyver
import (
_ "embed"
"github.com/akmalfairuz/legacy-version/internal/chunk"
"github.com/akmalfairuz/legacy-version/legacyver/proto"
"github.com/akmalfairuz/legacy-version/mapping"
)
const (
// ItemVersion712 ...
ItemVersion712 = 201
// BlockVersion712 ...
BlockVersion712 int32 = (1 << 24) | (21 << 16) | (20 << 8)
)
var (
//go:embed data/item_runtime_ids_712.nbt
itemRuntimeIDData712 []byte
//go:embed data/required_item_list_712.json
requiredItemList712 []byte
//go:embed data/block_states_712.nbt
blockStateData712 []byte
)
func New712(direct bool) *Protocol {
itemMapping := mapping.NewItemMapping(itemRuntimeIDData712, requiredItemList712, ItemVersion712, false)
blockMapping := mapping.NewBlockMapping(blockStateData712)
return &Protocol{
ver: "1.21.20",
id: proto.ID712,
blockTranslator: NewBlockTranslator(blockMapping, latestBlockMapping, chunk.NewNetworkPersistentEncoding(blockMapping, BlockVersion712), chunk.NewBlockPaletteEncoding(blockMapping, BlockVersion712), false),
itemTranslator: NewItemTranslator(itemMapping, itemMappingLatest, blockMapping, blockMappingLatest),
}
}