Add 1.21.2 & 1.21.0 support

This commit is contained in:
AkmalFairuz
2025-01-01 13:40:15 +07:00
parent 123f125d4e
commit f6548dd6a7
29 changed files with 7641 additions and 7 deletions

View File

@@ -0,0 +1,56 @@
package proto
import "github.com/sandertv/gophertunnel/minecraft/protocol"
// EntityLink is a link between two entities, typically being one entity riding another.
type EntityLink struct {
// RiddenEntityUniqueID is the entity unique ID of the entity that is being ridden. For a player sitting
// in a boat, this is the unique ID of the boat.
RiddenEntityUniqueID int64
// RiderEntityUniqueID is the entity unique ID of the entity that is riding. For a player sitting in a
// boat, this is the unique ID of the player.
RiderEntityUniqueID int64
// Type is one of the types above. It specifies the way the entity is linked to another entity.
Type byte
// Immediate is set to immediately dismount an entity from another. This should be set when the mount of
// an entity is killed.
Immediate bool
// RiderInitiated specifies if the link was created by the rider, for example the player starting to ride
// a horse by itself. This is generally true in vanilla environment for players.
RiderInitiated bool
// VehicleAngularVelocity is the angular velocity of the vehicle that the rider is riding.
VehicleAngularVelocity float32
}
func (x *EntityLink) FromLatest(link protocol.EntityLink) EntityLink {
x.RiddenEntityUniqueID = link.RiddenEntityUniqueID
x.RiderEntityUniqueID = link.RiderEntityUniqueID
x.Type = link.Type
x.Immediate = link.Immediate
x.RiderInitiated = link.RiderInitiated
x.VehicleAngularVelocity = link.VehicleAngularVelocity
return *x
}
func (x *EntityLink) ToLatest() protocol.EntityLink {
return protocol.EntityLink{
RiddenEntityUniqueID: x.RiddenEntityUniqueID,
RiderEntityUniqueID: x.RiderEntityUniqueID,
Type: x.Type,
Immediate: x.Immediate,
RiderInitiated: x.RiderInitiated,
VehicleAngularVelocity: x.VehicleAngularVelocity,
}
}
// Marshal encodes/decodes a single entity link.
func (x *EntityLink) Marshal(r protocol.IO) {
r.Varint64(&x.RiddenEntityUniqueID)
r.Varint64(&x.RiderEntityUniqueID)
r.Uint8(&x.Type)
r.Bool(&x.Immediate)
r.Bool(&x.RiderInitiated)
if IsProtoGTE(r, ID712) {
r.Float32(&x.VehicleAngularVelocity)
}
}

View File

@@ -0,0 +1,158 @@
package proto
import (
"github.com/go-gl/mathgl/mgl32"
"github.com/sandertv/gophertunnel/minecraft/protocol"
)
// InventoryTransactionData represents an object that holds data specific to an inventory transaction type.
// The data it holds depends on the type.
type InventoryTransactionData interface {
// Marshal encodes/decodes a serialised inventory transaction data object.
Marshal(r protocol.IO)
}
// lookupTransactionData looks up inventory transaction data for the ID passed.
func lookupTransactionData(id uint32, x *InventoryTransactionData) bool {
switch id {
case protocol.InventoryTransactionTypeNormal:
*x = &protocol.NormalTransactionData{}
case protocol.InventoryTransactionTypeMismatch:
*x = &protocol.MismatchTransactionData{}
case protocol.InventoryTransactionTypeUseItem:
*x = &UseItemTransactionData{}
case protocol.InventoryTransactionTypeUseItemOnEntity:
*x = &protocol.UseItemOnEntityTransactionData{}
case protocol.InventoryTransactionTypeReleaseItem:
*x = &protocol.ReleaseItemTransactionData{}
default:
return false
}
return true
}
// lookupTransactionDataType looks up an ID for a specific transaction data.
func lookupTransactionDataType(x InventoryTransactionData, id *uint32) bool {
switch x.(type) {
case *protocol.NormalTransactionData:
*id = protocol.InventoryTransactionTypeNormal
case *protocol.MismatchTransactionData:
*id = protocol.InventoryTransactionTypeMismatch
case *UseItemTransactionData:
*id = protocol.InventoryTransactionTypeUseItem
case *protocol.UseItemOnEntityTransactionData:
*id = protocol.InventoryTransactionTypeUseItemOnEntity
case *protocol.ReleaseItemTransactionData:
*id = protocol.InventoryTransactionTypeReleaseItem
default:
return false
}
return true
}
// UseItemTransactionData represents an inventory transaction data object sent when the client uses an item on
// a block.
type UseItemTransactionData struct {
// LegacyRequestID is an ID that is only non-zero at times when sent by the client. The server should
// always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values
// in it.
// LegacyRequestID ties in with the ItemStackResponse packet. If this field is non-0, the server should
// respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the
// hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it.
LegacyRequestID int32
// LegacySetItemSlots are only present if the LegacyRequestID is non-zero. These item slots inform the
// server of the slots that were changed during the inventory transaction, and the server should send
// back an ItemStackResponse packet with these slots present in it. (Or false with no slots, if rejected.)
LegacySetItemSlots []protocol.LegacySetItemSlot
// Actions is a list of actions that took place, that form the inventory transaction together. Each of
// these actions hold one slot in which one item was changed to another. In general, the combination of
// all of these actions results in a balanced inventory transaction. This should be checked to ensure that
// no items are cheated into the inventory.
Actions []protocol.InventoryAction
// ActionType is the type of the UseItem inventory transaction. It is one of the action types found above,
// and specifies the way the player interacted with the block.
ActionType uint32
// TriggerType is the type of the trigger that caused the inventory transaction. It is one of the trigger
// types found in the constants above. If TriggerType is TriggerTypePlayerInput, the transaction is from
// the initial input of the player. If it is TriggerTypeSimulationTick, the transaction is from a simulation
// tick when the player is holding down the input.
TriggerType uint32
// BlockPosition is the position of the block that was interacted with. This is only really a correct
// block position if ActionType is not UseItemActionClickAir.
BlockPosition protocol.BlockPos
// BlockFace is the face of the block that was interacted with. When clicking the block, it is the face
// clicked. When breaking the block, it is the face that was last being hit until the block broke.
BlockFace int32
// HotBarSlot is the hot bar slot that the player was holding while clicking the block. It should be used
// to ensure that the hot bar slot and held item are correctly synchronised with the server.
HotBarSlot int32
// HeldItem is the item that was held to interact with the block. The server should check if this item
// is actually present in the HotBarSlot.
HeldItem protocol.ItemInstance
// Position is the position of the player at the time of interaction. For clicking a block, this is the
// position at that time, whereas for breaking the block it is the position at the time of breaking.
Position mgl32.Vec3
// ClickedPosition is the position that was clicked relative to the block's base coordinate. It can be
// used to find out exactly where a player clicked the block.
ClickedPosition mgl32.Vec3
// BlockRuntimeID is the runtime ID of the block that was clicked. It may be used by the server to verify
// that the player's world client-side is synchronised with the server's.
BlockRuntimeID uint32
// ClientPrediction is the client's prediction on the output of the transaction. It is one of the client
// prediction found in the constants above.
ClientPrediction uint32
}
func (x *UseItemTransactionData) FromLatest(l *protocol.UseItemTransactionData) *UseItemTransactionData {
return &UseItemTransactionData{
LegacyRequestID: l.LegacyRequestID,
LegacySetItemSlots: l.LegacySetItemSlots,
Actions: l.Actions,
ActionType: l.ActionType,
TriggerType: l.TriggerType,
BlockPosition: l.BlockPosition,
BlockFace: l.BlockFace,
HotBarSlot: l.HotBarSlot,
HeldItem: l.HeldItem,
Position: l.Position,
ClickedPosition: l.ClickedPosition,
BlockRuntimeID: l.BlockRuntimeID,
ClientPrediction: l.ClientPrediction,
}
}
func (x *UseItemTransactionData) ToLatest() *protocol.UseItemTransactionData {
return &protocol.UseItemTransactionData{
LegacyRequestID: x.LegacyRequestID,
LegacySetItemSlots: x.LegacySetItemSlots,
Actions: x.Actions,
ActionType: x.ActionType,
TriggerType: x.TriggerType,
BlockPosition: x.BlockPosition,
BlockFace: x.BlockFace,
HotBarSlot: x.HotBarSlot,
HeldItem: x.HeldItem,
Position: x.Position,
ClickedPosition: x.ClickedPosition,
BlockRuntimeID: x.BlockRuntimeID,
ClientPrediction: x.ClientPrediction,
}
}
// Marshal ...
func (x *UseItemTransactionData) Marshal(r protocol.IO) {
r.Varuint32(&x.ActionType)
if IsProtoGTE(r, ID712) {
r.Varuint32(&x.TriggerType)
}
r.UBlockPos(&x.BlockPosition)
r.Varint32(&x.BlockFace)
r.Varint32(&x.HotBarSlot)
r.ItemInstance(&x.HeldItem)
r.Vec3(&x.Position)
r.Vec3(&x.ClickedPosition)
r.Varuint32(&x.BlockRuntimeID)
if IsProtoGTE(r, ID712) {
r.Varuint32(&x.ClientPrediction)
}
}

View File

@@ -1,6 +1,7 @@
package proto
import (
"fmt"
"github.com/sandertv/gophertunnel/minecraft/protocol"
)
@@ -57,3 +58,41 @@ func EmptySlice[T any](io protocol.IO, slice *[]T) {
*slice = make([]T, 0)
}
}
func TransactionDataType(io protocol.IO, x *InventoryTransactionData) {
if IsReader(io) {
var transactionType uint32
io.Varuint32(&transactionType)
if !lookupTransactionData(transactionType, x) {
io.UnknownEnumOption(transactionType, "inventory transaction data type")
}
} else {
var id uint32
if !lookupTransactionDataType(*x, &id) {
io.UnknownEnumOption(fmt.Sprintf("%T", x), "inventory transaction data type")
}
io.Varuint32(&id)
}
}
func PlayerInventoryAction(io protocol.IO, x *protocol.UseItemTransactionData) {
io.Varint32(&x.LegacyRequestID)
if x.LegacyRequestID < -1 && (x.LegacyRequestID&1) == 0 {
protocol.Slice(io, &x.LegacySetItemSlots)
}
protocol.Slice(io, &x.Actions)
io.Varuint32(&x.ActionType)
if IsProtoGTE(io, ID712) {
io.Varuint32(&x.TriggerType)
}
io.BlockPos(&x.BlockPosition)
io.Varint32(&x.BlockFace)
io.Varint32(&x.HotBarSlot)
io.ItemInstance(&x.HeldItem)
io.Vec3(&x.Position)
io.Vec3(&x.ClickedPosition)
io.Varuint32(&x.BlockRuntimeID)
if IsProtoGTE(io, ID712) {
io.Varuint32(&x.ClientPrediction)
}
}

View File

@@ -538,7 +538,9 @@ type CraftRecipeStackRequestAction struct {
// Marshal ...
func (a *CraftRecipeStackRequestAction) Marshal(r protocol.IO) {
r.Varuint32(&a.RecipeNetworkID)
r.Uint8(&a.NumberOfCrafts)
if IsProtoGTE(r, ID712) {
r.Uint8(&a.NumberOfCrafts)
}
}
// AutoCraftRecipeStackRequestAction is sent by the client similarly to the CraftRecipeStackRequestAction. The

View File

@@ -87,7 +87,9 @@ func (x *TexturePackInfo) Marshal(r protocol.IO) {
r.String(&x.SubPackName)
r.String(&x.ContentIdentity)
r.Bool(&x.HasScripts)
r.Bool(&x.AddonPack)
if IsProtoGTE(r, ID712) {
r.Bool(&x.AddonPack)
}
r.Bool(&x.RTXEnabled)
if IsProtoGTE(r, ID748) {
r.String(&x.DownloadURL)