Add 1.21.2 & 1.21.0 support
This commit is contained in:
12
README.md
12
README.md
@@ -9,8 +9,16 @@ A gophertunnel protocol interface implementation to support older Minecraft Bedr
|
||||
| 748 | 1.21.40 | ✅ |
|
||||
| 729 | 1.21.30 | ✅ |
|
||||
| 712 | 1.21.20 | ✅ |
|
||||
| 686 | 1.21.2 | 🚧 |
|
||||
| 685 | 1.21.0 | 🚧 |
|
||||
| 686 | 1.21.2 | ✅ |
|
||||
| 685 | 1.21.0 | ✅ |
|
||||
| 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 | 🚧 |
|
||||
|
||||
## Credits
|
||||
- [Flonja/multiversion](https://github.com/Flonja/multiversion)
|
||||
|
||||
BIN
legacyver/data/block_states_686.nbt
Normal file
BIN
legacyver/data/block_states_686.nbt
Normal file
Binary file not shown.
BIN
legacyver/data/item_runtime_ids_686.nbt
Normal file
BIN
legacyver/data/item_runtime_ids_686.nbt
Normal file
Binary file not shown.
6398
legacyver/data/required_item_list_686.json
Normal file
6398
legacyver/data/required_item_list_686.json
Normal file
File diff suppressed because it is too large
Load Diff
76
legacyver/legacypacket/add_actor.go
Normal file
76
legacyver/legacypacket/add_actor.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// AddActor is sent by the server to the client to spawn an entity to the player. It is used for every entity
|
||||
// except other players, for which the AddPlayer packet is used.
|
||||
type AddActor struct {
|
||||
// EntityUniqueID is the unique ID of the entity. The unique ID is a value that remains consistent across
|
||||
// different sessions of the same world, but most servers simply fill the runtime ID of the entity out for
|
||||
// this field.
|
||||
EntityUniqueID int64
|
||||
// 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
|
||||
// EntityType is the string entity type of the entity, for example 'minecraft:skeleton'. A list of these
|
||||
// entities may be found online.
|
||||
EntityType string
|
||||
// Position is the position to spawn the entity on. If the entity is on a distance that the player cannot
|
||||
// see it, the entity will still show up if the player moves closer.
|
||||
Position mgl32.Vec3
|
||||
// Velocity is the initial velocity the entity spawns with. This velocity will initiate client side
|
||||
// movement of the entity.
|
||||
Velocity mgl32.Vec3
|
||||
// Pitch is the vertical rotation of the entity. Facing straight forward yields a pitch of 0. Pitch is
|
||||
// measured in degrees.
|
||||
Pitch float32
|
||||
// Yaw is the horizontal rotation of the entity. Yaw is also measured in degrees.
|
||||
Yaw float32
|
||||
// HeadYaw is the same as Yaw, except that it applies specifically to the head of the entity. A different value for
|
||||
// HeadYaw than Yaw means that the entity will have its head turned.
|
||||
HeadYaw float32
|
||||
// BodyYaw is the same as Yaw, except that it applies specifically to the body of the entity. A different value for
|
||||
// BodyYaw than HeadYaw means that the entity will have its body turned, although it is unclear what the difference
|
||||
// between BodyYaw and Yaw is.
|
||||
BodyYaw float32
|
||||
// Attributes is a slice of attributes that the entity has. It includes attributes such as its health,
|
||||
// movement speed, etc.
|
||||
Attributes []protocol.AttributeValue
|
||||
// EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in
|
||||
// particular the way the entity looks. Flags include ones such as 'on fire' and 'sprinting'.
|
||||
// The metadata values are indexed by their property key.
|
||||
EntityMetadata map[uint32]any
|
||||
// EntityProperties is a list of properties that the entity inhibits. These properties define and alter specific
|
||||
// attributes of the entity.
|
||||
EntityProperties protocol.EntityProperties
|
||||
// EntityLinks is a list of entity links that are currently active on the entity. These links alter the
|
||||
// way the entity shows up when first spawned in terms of it shown as riding an entity. Setting these
|
||||
// links is important for new viewers to see the entity is riding another entity.
|
||||
EntityLinks []proto.EntityLink
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*AddActor) ID() uint32 {
|
||||
return packet.IDAddActor
|
||||
}
|
||||
|
||||
func (pk *AddActor) Marshal(io protocol.IO) {
|
||||
io.Varint64(&pk.EntityUniqueID)
|
||||
io.Varuint64(&pk.EntityRuntimeID)
|
||||
io.String(&pk.EntityType)
|
||||
io.Vec3(&pk.Position)
|
||||
io.Vec3(&pk.Velocity)
|
||||
io.Float32(&pk.Pitch)
|
||||
io.Float32(&pk.Yaw)
|
||||
io.Float32(&pk.HeadYaw)
|
||||
io.Float32(&pk.BodyYaw)
|
||||
protocol.Slice(io, &pk.Attributes)
|
||||
io.EntityMetadata(&pk.EntityMetadata)
|
||||
protocol.Single(io, &pk.EntityProperties)
|
||||
protocol.Slice(io, &pk.EntityLinks)
|
||||
}
|
||||
92
legacyver/legacypacket/add_player.go
Normal file
92
legacyver/legacypacket/add_player.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// AddPlayer is sent by the server to the client to make a player entity show up client-side. It is one of the
|
||||
// few entities that cannot be sent using the AddActor packet.
|
||||
type AddPlayer struct {
|
||||
// UUID is the UUID of the player. It is the same UUID that the client sent in the Login packet at the
|
||||
// start of the session. A player with this UUID must exist in the player list (built up using the
|
||||
// PlayerList packet), for it to show up in-game.
|
||||
UUID uuid.UUID
|
||||
// Username is the name of the player. This username is the username that will be set as the initial
|
||||
// name tag of the player.
|
||||
Username string
|
||||
// EntityRuntimeID is the runtime ID of the player. The runtime ID is unique for each world session, and
|
||||
// entities are generally identified in packets using this runtime ID.
|
||||
EntityRuntimeID uint64
|
||||
// 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
|
||||
// Position is the position to spawn the player on. If the player is on a distance that the viewer cannot
|
||||
// see it, the player will still show up if the viewer moves closer.
|
||||
Position mgl32.Vec3
|
||||
// Velocity is the initial velocity the player spawns with. This velocity will initiate client side
|
||||
// movement of the player.
|
||||
Velocity mgl32.Vec3
|
||||
// Pitch is the vertical rotation of the player. Facing straight forward yields a pitch of 0. Pitch is
|
||||
// measured in degrees.
|
||||
Pitch float32
|
||||
// Yaw is the horizontal rotation of the player. Yaw is also measured in degrees.
|
||||
Yaw float32
|
||||
// HeadYaw is the same as Yaw, except that it applies specifically to the head of the player. A different
|
||||
// value for HeadYaw than Yaw means that the player will have its head turned.
|
||||
HeadYaw float32
|
||||
// HeldItem is the item that the player is holding. The item is shown to the viewer as soon as the player
|
||||
// itself shows up. Needless to say that this field is rather pointless, as additional packets still must
|
||||
// be sent for armour to show up.
|
||||
HeldItem protocol.ItemInstance
|
||||
// GameType is the game type of the player. If set to GameTypeSpectator, the player will not be shown to viewers.
|
||||
GameType int32
|
||||
// EntityMetadata is a map of entity metadata, which includes flags and data properties that alter in
|
||||
// particular the way the player looks. Flags include ones such as 'on fire' and 'sprinting'.
|
||||
// The metadata values are indexed by their property key.
|
||||
EntityMetadata map[uint32]any
|
||||
// EntityProperties is a list of properties that the entity inhibits. These properties define and alter specific
|
||||
// attributes of the entity.
|
||||
EntityProperties protocol.EntityProperties
|
||||
// AbilityData represents various data about the abilities of a player, such as ability layers or permissions.
|
||||
AbilityData protocol.AbilityData
|
||||
// EntityLinks is a list of entity links that are currently active on the player. These links alter the
|
||||
// way the player shows up when first spawned in terms of it shown as riding an entity. Setting these
|
||||
// links is important for new viewers to see the player is riding another entity.
|
||||
EntityLinks []proto.EntityLink
|
||||
// DeviceID is the device ID set in one of the files found in the storage of the device of the player. It
|
||||
// may be changed freely, so it should not be relied on for anything.
|
||||
DeviceID string
|
||||
// BuildPlatform is the build platform/device OS of the player that is about to be added, as it sent in
|
||||
// the Login packet when joining.
|
||||
BuildPlatform int32
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*AddPlayer) ID() uint32 {
|
||||
return packet.IDAddPlayer
|
||||
}
|
||||
|
||||
func (pk *AddPlayer) Marshal(io protocol.IO) {
|
||||
io.UUID(&pk.UUID)
|
||||
io.String(&pk.Username)
|
||||
io.Varuint64(&pk.EntityRuntimeID)
|
||||
io.String(&pk.PlatformChatID)
|
||||
io.Vec3(&pk.Position)
|
||||
io.Vec3(&pk.Velocity)
|
||||
io.Float32(&pk.Pitch)
|
||||
io.Float32(&pk.Yaw)
|
||||
io.Float32(&pk.HeadYaw)
|
||||
io.ItemInstance(&pk.HeldItem)
|
||||
io.Varint32(&pk.GameType)
|
||||
io.EntityMetadata(&pk.EntityMetadata)
|
||||
protocol.Single(io, &pk.EntityProperties)
|
||||
protocol.Single(io, &pk.AbilityData)
|
||||
protocol.Slice(io, &pk.EntityLinks)
|
||||
io.String(&pk.DeviceID)
|
||||
io.Int32(&pk.BuildPlatform)
|
||||
}
|
||||
36
legacyver/legacypacket/camera_instruction.go
Normal file
36
legacyver/legacypacket/camera_instruction.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// CameraInstruction gives a custom camera specific instructions to operate.
|
||||
type CameraInstruction struct {
|
||||
// Set is a camera instruction that sets the camera to a specified preset.
|
||||
Set protocol.Optional[protocol.CameraInstructionSet]
|
||||
// Clear can be set to true to clear all the current camera instructions.
|
||||
Clear protocol.Optional[bool]
|
||||
// Fade is a camera instruction that fades the screen to a specified colour.
|
||||
Fade protocol.Optional[protocol.CameraInstructionFade]
|
||||
// Target is a camera instruction that targets a specific entity.
|
||||
Target protocol.Optional[protocol.CameraInstructionTarget]
|
||||
// RemoveTarget can be set to true to remove the current aim assist target.
|
||||
RemoveTarget protocol.Optional[bool]
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*CameraInstruction) ID() uint32 {
|
||||
return packet.IDCameraInstruction
|
||||
}
|
||||
|
||||
func (pk *CameraInstruction) Marshal(io protocol.IO) {
|
||||
protocol.OptionalMarshaler(io, &pk.Set)
|
||||
protocol.OptionalFunc(io, &pk.Clear, io.Bool)
|
||||
protocol.OptionalMarshaler(io, &pk.Fade)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
protocol.OptionalMarshaler(io, &pk.Target)
|
||||
protocol.OptionalFunc(io, &pk.RemoveTarget, io.Bool)
|
||||
}
|
||||
}
|
||||
46
legacyver/legacypacket/change_dimension.go
Normal file
46
legacyver/legacypacket/change_dimension.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// ChangeDimension is sent by the server to the client to send a dimension change screen client-side. Once the
|
||||
// screen is cleared client-side, the client will send a PlayerAction packet with
|
||||
// PlayerActionDimensionChangeDone.
|
||||
type ChangeDimension struct {
|
||||
// Dimension is the dimension that the client should be changed to. The fog colour will change depending
|
||||
// on the type of dimension, which is one of the constants above.
|
||||
// Note that Dimension MUST be a different dimension than the one that the player is currently in. Sending
|
||||
// a ChangeDimension packet with a Dimension that the player is currently in will result in a never-ending
|
||||
// dimension change screen.
|
||||
Dimension int32
|
||||
// Position is the position in the new dimension that the player is spawned in.
|
||||
Position mgl32.Vec3
|
||||
// Respawn specifies if the dimension change was respawn based, meaning that the player died in one
|
||||
// dimension and got respawned into another. The client will send a PlayerAction packet with
|
||||
// PlayerActionDimensionChangeRequest if it dies in another dimension, indicating that it needs a
|
||||
// DimensionChange packet with Respawn set to true.
|
||||
Respawn bool
|
||||
// LoadingScreenID is a unique ID for the loading screen that the player is currently in. The client will
|
||||
// update the server on its state through the ServerBoundLoadingScreen packet, and it can be used to not
|
||||
// send specific packets to the client if it is changing dimensions. This field should be unique for every
|
||||
//ChangeDimension packet sent.
|
||||
LoadingScreenID protocol.Optional[uint32]
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*ChangeDimension) ID() uint32 {
|
||||
return packet.IDChangeDimension
|
||||
}
|
||||
|
||||
func (pk *ChangeDimension) Marshal(io protocol.IO) {
|
||||
io.Varint32(&pk.Dimension)
|
||||
io.Vec3(&pk.Position)
|
||||
io.Bool(&pk.Respawn)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
protocol.OptionalFunc(io, &pk.LoadingScreenID, io.Uint32)
|
||||
}
|
||||
}
|
||||
50
legacyver/legacypacket/correct_player_move_prediction.go
Normal file
50
legacyver/legacypacket/correct_player_move_prediction.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// CorrectPlayerMovePrediction is sent by the server if and only if StartGame.ServerAuthoritativeMovementMode
|
||||
// is set to AuthoritativeMovementModeServerWithRewind. The packet is used to correct movement at a specific
|
||||
// point in time.
|
||||
type CorrectPlayerMovePrediction struct {
|
||||
// PredictionType is the type of prediction that was corrected. It is one of the constants above.
|
||||
PredictionType byte
|
||||
// Position is the position that the player is supposed to be at the tick written in the field below.
|
||||
// The client will change its current position based on movement after that tick starting from the
|
||||
// Position.
|
||||
Position mgl32.Vec3
|
||||
// Delta is the change in position compared to what the client sent as its position at that specific tick.
|
||||
Delta mgl32.Vec3
|
||||
// Rotation is the rotation of the player at the tick written in the field below. It is only included if
|
||||
// PredictionType is PredictionTypeVehicle.
|
||||
Rotation mgl32.Vec2
|
||||
// VehicleAngularVelocity is the angular velocity of the vehicle that the rider is riding.
|
||||
VehicleAngularVelocity protocol.Optional[float32]
|
||||
// OnGround specifies if the player was on the ground at the time of the tick below.
|
||||
OnGround bool
|
||||
// Tick is the tick of the movement which was corrected by this packet.
|
||||
Tick uint64
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*CorrectPlayerMovePrediction) ID() uint32 {
|
||||
return packet.IDCorrectPlayerMovePrediction
|
||||
}
|
||||
|
||||
func (pk *CorrectPlayerMovePrediction) Marshal(io protocol.IO) {
|
||||
io.Uint8(&pk.PredictionType)
|
||||
io.Vec3(&pk.Position)
|
||||
io.Vec3(&pk.Delta)
|
||||
if pk.PredictionType == packet.PredictionTypeVehicle {
|
||||
io.Vec2(&pk.Rotation)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
protocol.OptionalFunc(io, &pk.VehicleAngularVelocity, io.Float32)
|
||||
}
|
||||
}
|
||||
io.Bool(&pk.OnGround)
|
||||
io.Varuint64(&pk.Tick)
|
||||
}
|
||||
40
legacyver/legacypacket/disconnect.go
Normal file
40
legacyver/legacypacket/disconnect.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// Disconnect may be sent by the server to disconnect the client using an optional message to send as the
|
||||
// disconnect screen.
|
||||
type Disconnect struct {
|
||||
// Reason is the reason for the disconnection. It seems as if this field has no use other than for
|
||||
// telemetry reasons as it does not affect the message that gets displayed on the disconnect screen.
|
||||
Reason int32
|
||||
// HideDisconnectionScreen specifies if the disconnection screen should be hidden when the client is
|
||||
// disconnected, meaning it will be sent directly to the main menu.
|
||||
HideDisconnectionScreen bool
|
||||
// Message is an optional message to show when disconnected. This message is only written if the
|
||||
// HideDisconnectionScreen field is set to true.
|
||||
Message string
|
||||
// FilteredMessage is a filtered version of Message with all the profanity removed. The client will use
|
||||
// this over Message if this field is not empty and they have the "Filter Profanity" setting enabled.
|
||||
FilteredMessage string
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*Disconnect) ID() uint32 {
|
||||
return packet.IDDisconnect
|
||||
}
|
||||
|
||||
func (pk *Disconnect) Marshal(io protocol.IO) {
|
||||
io.Varint32(&pk.Reason)
|
||||
io.Bool(&pk.HideDisconnectionScreen)
|
||||
if !pk.HideDisconnectionScreen {
|
||||
io.String(&pk.Message)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.String(&pk.FilteredMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
29
legacyver/legacypacket/editor_network.go
Normal file
29
legacyver/legacypacket/editor_network.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/nbt"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// EditorNetwork is a packet sent from the server to the client and vise-versa to communicate editor-mode related
|
||||
// information. It carries a single compound tag containing the relevant information.
|
||||
type EditorNetwork struct {
|
||||
// RouteToManager ...
|
||||
RouteToManager bool
|
||||
// Payload is a network little endian compound tag holding data relevant to the editor.
|
||||
Payload map[string]any
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*EditorNetwork) ID() uint32 {
|
||||
return packet.IDEditorNetwork
|
||||
}
|
||||
|
||||
func (pk *EditorNetwork) Marshal(io protocol.IO) {
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.Bool(&pk.RouteToManager)
|
||||
}
|
||||
io.NBT(&pk.Payload, nbt.NetworkLittleEndian)
|
||||
}
|
||||
@@ -40,6 +40,8 @@ func (pk *InventoryContent) Marshal(io protocol.IO) {
|
||||
if proto.IsProtoGTE(io, proto.ID748) {
|
||||
io.ItemInstance(&pk.StorageItem)
|
||||
} else {
|
||||
io.Varuint32(&pk.DynamicContainerSize)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.Varuint32(&pk.DynamicContainerSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,9 @@ func (pk *InventorySlot) Marshal(io protocol.IO) {
|
||||
if proto.IsProtoGTE(io, proto.ID748) {
|
||||
io.ItemInstance(&pk.StorageItem)
|
||||
} else {
|
||||
io.Varuint32(&pk.DynamicContainerSize)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.Varuint32(&pk.DynamicContainerSize)
|
||||
}
|
||||
}
|
||||
io.ItemInstance(&pk.NewItem)
|
||||
}
|
||||
|
||||
50
legacyver/legacypacket/inventory_transaction.go
Normal file
50
legacyver/legacypacket/inventory_transaction.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// InventoryTransaction is a packet sent by the client. It essentially exists out of multiple sub-packets,
|
||||
// each of which have something to do with the inventory in one way or another. Some of these sub-packets
|
||||
// directly relate to the inventory, others relate to interaction with the world, that could potentially
|
||||
// result in a change in the inventory.
|
||||
type InventoryTransaction 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
|
||||
// TransactionData is a data object that holds data specific to the type of transaction that the
|
||||
// TransactionPacket held. Its concrete type must be one of NormalTransactionData, MismatchTransactionData
|
||||
// UseItemTransactionData, UseItemOnEntityTransactionData or ReleaseItemTransactionData. If nil is set,
|
||||
// the transaction will be assumed to of type InventoryTransactionTypeNormal.
|
||||
TransactionData proto.InventoryTransactionData
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*InventoryTransaction) ID() uint32 {
|
||||
return packet.IDInventoryTransaction
|
||||
}
|
||||
|
||||
func (pk *InventoryTransaction) Marshal(io protocol.IO) {
|
||||
io.Varint32(&pk.LegacyRequestID)
|
||||
if pk.LegacyRequestID != 0 {
|
||||
protocol.Slice(io, &pk.LegacySetItemSlots)
|
||||
}
|
||||
proto.TransactionDataType(io, &pk.TransactionData)
|
||||
protocol.Slice(io, &pk.Actions)
|
||||
pk.TransactionData.Marshal(io)
|
||||
}
|
||||
44
legacyver/legacypacket/mob_armour_equipment.go
Normal file
44
legacyver/legacypacket/mob_armour_equipment.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// MobArmourEquipment is sent by the server to the client to update the armour an entity is wearing. It is
|
||||
// sent for both players and other entities, such as zombies.
|
||||
type MobArmourEquipment 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
|
||||
// Helmet is the equipped helmet of the entity. Items that are not wearable on the head will not be
|
||||
// rendered by the client. Unlike in Java Edition, blocks cannot be worn.
|
||||
Helmet protocol.ItemInstance
|
||||
// Chestplate is the chestplate of the entity. Items that are not wearable as chestplate will not be
|
||||
// rendered.
|
||||
Chestplate protocol.ItemInstance
|
||||
// Leggings is the item worn as leggings by the entity. Items not wearable as leggings will not be
|
||||
// rendered client-side.
|
||||
Leggings protocol.ItemInstance
|
||||
// Boots is the item worn as boots by the entity. Items not wearable as boots will not be rendered.
|
||||
Boots protocol.ItemInstance
|
||||
// Body is the item worn on the body of the entity. Items not wearable on the body will not be rendered.
|
||||
Body protocol.ItemInstance
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*MobArmourEquipment) ID() uint32 {
|
||||
return packet.IDMobArmourEquipment
|
||||
}
|
||||
|
||||
func (pk *MobArmourEquipment) Marshal(io protocol.IO) {
|
||||
io.Varuint64(&pk.EntityRuntimeID)
|
||||
io.ItemInstance(&pk.Helmet)
|
||||
io.ItemInstance(&pk.Chestplate)
|
||||
io.ItemInstance(&pk.Leggings)
|
||||
io.ItemInstance(&pk.Boots)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.ItemInstance(&pk.Body)
|
||||
}
|
||||
}
|
||||
63
legacyver/legacypacket/player_armour_damage.go
Normal file
63
legacyver/legacypacket/player_armour_damage.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// PlayerArmourDamage is sent by the server to damage the armour of a player. It is a very efficient packet,
|
||||
// but generally it's much easier to just send a slot update for the damaged armour.
|
||||
type PlayerArmourDamage struct {
|
||||
// Bitset holds a bitset of 4 bits that indicate which pieces of armour need to have damage dealt to them.
|
||||
// The first bit, when toggled, is for a helmet, the second for the chestplate, the third for the leggings
|
||||
// and the fourth for boots.
|
||||
Bitset uint8
|
||||
// HelmetDamage is the amount of damage that should be dealt to the helmet.
|
||||
HelmetDamage int32
|
||||
// ChestplateDamage is the amount of damage that should be dealt to the chestplate.
|
||||
ChestplateDamage int32
|
||||
// LeggingsDamage is the amount of damage that should be dealt to the leggings.
|
||||
LeggingsDamage int32
|
||||
// BootsDamage is the amount of damage that should be dealt to the boots.
|
||||
BootsDamage int32
|
||||
// BodyDamage is the amount of damage that should be dealt to the body.
|
||||
BodyDamage int32
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (pk *PlayerArmourDamage) ID() uint32 {
|
||||
return packet.IDPlayerArmourDamage
|
||||
}
|
||||
|
||||
func (pk *PlayerArmourDamage) Marshal(io protocol.IO) {
|
||||
io.Uint8(&pk.Bitset)
|
||||
if pk.Bitset&packet.PlayerArmourDamageFlagHelmet != 0 {
|
||||
io.Varint32(&pk.HelmetDamage)
|
||||
} else {
|
||||
pk.HelmetDamage = 0
|
||||
}
|
||||
if pk.Bitset&packet.PlayerArmourDamageFlagChestplate != 0 {
|
||||
io.Varint32(&pk.ChestplateDamage)
|
||||
} else {
|
||||
pk.ChestplateDamage = 0
|
||||
}
|
||||
if pk.Bitset&packet.PlayerArmourDamageFlagLeggings != 0 {
|
||||
io.Varint32(&pk.LeggingsDamage)
|
||||
} else {
|
||||
pk.LeggingsDamage = 0
|
||||
}
|
||||
if pk.Bitset&packet.PlayerArmourDamageFlagBoots != 0 {
|
||||
io.Varint32(&pk.BootsDamage)
|
||||
} else {
|
||||
pk.BootsDamage = 0
|
||||
}
|
||||
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
if pk.Bitset&packet.PlayerArmourDamageFlagBody != 0 {
|
||||
io.Varint32(&pk.BodyDamage)
|
||||
} else {
|
||||
pk.BodyDamage = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ func (pk *PlayerAuthInput) Marshal(io protocol.IO) {
|
||||
io.Vec3(&pk.Delta)
|
||||
|
||||
if pk.InputData.Load(packet.InputFlagPerformItemInteraction) {
|
||||
io.PlayerInventoryAction(&pk.ItemInteractionData)
|
||||
proto.PlayerInventoryAction(io, &pk.ItemInteractionData)
|
||||
}
|
||||
|
||||
if pk.InputData.Load(packet.InputFlagPerformItemStackRequest) {
|
||||
|
||||
25
legacyver/legacypacket/set_actor_link.go
Normal file
25
legacyver/legacypacket/set_actor_link.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// SetActorLink is sent by the server to initiate an entity link client-side, meaning one entity will start
|
||||
// riding another.
|
||||
type SetActorLink struct {
|
||||
// EntityLink is the link to be set client-side. It links two entities together, so that one entity rides
|
||||
// another. Note that players that see those entities later will not see the link, unless it is also sent
|
||||
// in the AddActor and AddPlayer packets.
|
||||
EntityLink proto.EntityLink
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*SetActorLink) ID() uint32 {
|
||||
return packet.IDSetActorLink
|
||||
}
|
||||
|
||||
func (pk *SetActorLink) Marshal(io protocol.IO) {
|
||||
protocol.Single(io, &pk.EntityLink)
|
||||
}
|
||||
53
legacyver/legacypacket/set_title.go
Normal file
53
legacyver/legacypacket/set_title.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// SetTitle is sent by the server to make a title, subtitle or action bar shown to a player. It has several
|
||||
// fields that allow setting the duration of the titles.
|
||||
type SetTitle struct {
|
||||
// ActionType is the type of the action that should be executed upon the title of a player. It is one of
|
||||
// the constants above and specifies the response of the client to the packet.
|
||||
ActionType int32
|
||||
// Text is the text of the title, which has a different meaning depending on the ActionType that the
|
||||
// packet has. The text is the text of a title, subtitle or action bar, depending on the type set.
|
||||
Text string
|
||||
// FadeInDuration is the duration that the title takes to fade in on the screen of the player. It is
|
||||
// measured in 20ths of a second (AKA in ticks).
|
||||
FadeInDuration int32
|
||||
// RemainDuration is the duration that the title remains on the screen of the player. It is measured in
|
||||
// 20ths of a second (AKA in ticks).
|
||||
RemainDuration int32
|
||||
// FadeOutDuration is the duration that the title takes to fade out of the screen of the player. It is
|
||||
// measured in 20ths of a second (AKA in ticks).
|
||||
FadeOutDuration int32
|
||||
// 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. It is empty if the user is not logged into its XBL account.
|
||||
XUID string
|
||||
// PlatformOnlineID is either a uint64 or an empty string.
|
||||
PlatformOnlineID string
|
||||
// FilteredMessage is a filtered version of Message with all the profanity removed. The client will use
|
||||
// this over Message if this field is not empty and they have the "Filter Profanity" setting enabled.
|
||||
FilteredMessage string
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*SetTitle) ID() uint32 {
|
||||
return packet.IDSetTitle
|
||||
}
|
||||
|
||||
func (pk *SetTitle) Marshal(io protocol.IO) {
|
||||
io.Varint32(&pk.ActionType)
|
||||
io.String(&pk.Text)
|
||||
io.Varint32(&pk.FadeInDuration)
|
||||
io.Varint32(&pk.RemainDuration)
|
||||
io.Varint32(&pk.FadeOutDuration)
|
||||
io.String(&pk.XUID)
|
||||
io.String(&pk.PlatformOnlineID)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.String(&pk.FilteredMessage)
|
||||
}
|
||||
}
|
||||
33
legacyver/legacypacket/stop_sound.go
Normal file
33
legacyver/legacypacket/stop_sound.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package legacypacket
|
||||
|
||||
import (
|
||||
"github.com/akmalfairuz/legacy-version/legacyver/proto"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol"
|
||||
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
|
||||
)
|
||||
|
||||
// StopSound is sent by the server to stop a sound playing to the player, such as a playing music disk track
|
||||
// or other long-lasting sounds.
|
||||
type StopSound struct {
|
||||
// SoundName is the name of the sound that should be stopped from playing. If no sound with this name is
|
||||
// currently active, the packet is ignored.
|
||||
SoundName string
|
||||
// StopAll specifies if all sounds currently playing to the player should be stopped. If set to true, the
|
||||
// SoundName field may be left empty.
|
||||
StopAll bool
|
||||
// StopMusicLegacy is currently unknown.
|
||||
StopMusicLegacy bool
|
||||
}
|
||||
|
||||
// ID ...
|
||||
func (*StopSound) ID() uint32 {
|
||||
return packet.IDStopSound
|
||||
}
|
||||
|
||||
func (pk *StopSound) Marshal(io protocol.IO) {
|
||||
io.String(&pk.SoundName)
|
||||
io.Bool(&pk.StopAll)
|
||||
if proto.IsProtoGTE(io, proto.ID712) {
|
||||
io.Bool(&pk.StopMusicLegacy)
|
||||
}
|
||||
}
|
||||
56
legacyver/proto/entity_link.go
Normal file
56
legacyver/proto/entity_link.go
Normal 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)
|
||||
}
|
||||
}
|
||||
158
legacyver/proto/inventory.go
Normal file
158
legacyver/proto/inventory.go
Normal 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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -233,6 +233,137 @@ func (p *Protocol) downgradePackets(pks []packet.Packet, conn *minecraft.Conn) [
|
||||
Port: pk.Port,
|
||||
ReloadWorld: pk.ReloadWorld,
|
||||
}
|
||||
case *packet.AddActor:
|
||||
links := make([]proto.EntityLink, len(pk.EntityLinks))
|
||||
for i, l := range pk.EntityLinks {
|
||||
links[i] = (&proto.EntityLink{}).FromLatest(l)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.AddActor{
|
||||
EntityUniqueID: pk.EntityUniqueID,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
EntityType: pk.EntityType,
|
||||
Position: pk.Position,
|
||||
Velocity: pk.Velocity,
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
HeadYaw: pk.HeadYaw,
|
||||
BodyYaw: pk.BodyYaw,
|
||||
Attributes: pk.Attributes,
|
||||
EntityMetadata: pk.EntityMetadata,
|
||||
EntityProperties: pk.EntityProperties,
|
||||
EntityLinks: links,
|
||||
}
|
||||
case *packet.AddPlayer:
|
||||
links := make([]proto.EntityLink, len(pk.EntityLinks))
|
||||
for i, l := range pk.EntityLinks {
|
||||
links[i] = (&proto.EntityLink{}).FromLatest(l)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.AddPlayer{
|
||||
UUID: pk.UUID,
|
||||
Username: pk.Username,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
PlatformChatID: pk.PlatformChatID,
|
||||
Position: pk.Position,
|
||||
Velocity: pk.Velocity,
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
HeadYaw: pk.HeadYaw,
|
||||
HeldItem: pk.HeldItem,
|
||||
GameType: pk.GameType,
|
||||
EntityMetadata: pk.EntityMetadata,
|
||||
EntityProperties: pk.EntityProperties,
|
||||
AbilityData: pk.AbilityData,
|
||||
EntityLinks: links,
|
||||
DeviceID: pk.DeviceID,
|
||||
BuildPlatform: pk.BuildPlatform,
|
||||
}
|
||||
case *packet.SetActorLink:
|
||||
pks[pkIndex] = &legacypacket.SetActorLink{
|
||||
EntityLink: (&proto.EntityLink{}).FromLatest(pk.EntityLink),
|
||||
}
|
||||
case *packet.CameraInstruction:
|
||||
pks[pkIndex] = &legacypacket.CameraInstruction{
|
||||
Set: pk.Set,
|
||||
Clear: pk.Clear,
|
||||
Fade: pk.Fade,
|
||||
Target: pk.Target,
|
||||
RemoveTarget: pk.RemoveTarget,
|
||||
}
|
||||
case *packet.ChangeDimension:
|
||||
pks[pkIndex] = &legacypacket.ChangeDimension{
|
||||
Dimension: pk.Dimension,
|
||||
Position: pk.Position,
|
||||
Respawn: pk.Respawn,
|
||||
LoadingScreenID: pk.LoadingScreenID,
|
||||
}
|
||||
case *packet.CorrectPlayerMovePrediction:
|
||||
pks[pkIndex] = &legacypacket.CorrectPlayerMovePrediction{
|
||||
PredictionType: pk.PredictionType,
|
||||
Position: pk.Position,
|
||||
Delta: pk.Delta,
|
||||
Rotation: pk.Rotation,
|
||||
VehicleAngularVelocity: pk.VehicleAngularVelocity,
|
||||
OnGround: pk.OnGround,
|
||||
Tick: pk.Tick,
|
||||
}
|
||||
case *packet.Disconnect:
|
||||
pks[pkIndex] = &legacypacket.Disconnect{
|
||||
Reason: pk.Reason,
|
||||
HideDisconnectionScreen: pk.HideDisconnectionScreen,
|
||||
Message: pk.Message,
|
||||
FilteredMessage: pk.FilteredMessage,
|
||||
}
|
||||
case *packet.EditorNetwork:
|
||||
pks[pkIndex] = &legacypacket.EditorNetwork{
|
||||
RouteToManager: pk.RouteToManager,
|
||||
Payload: pk.Payload,
|
||||
}
|
||||
case *packet.MobArmourEquipment:
|
||||
pks[pkIndex] = &legacypacket.MobArmourEquipment{
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
Helmet: pk.Helmet,
|
||||
Chestplate: pk.Chestplate,
|
||||
Leggings: pk.Leggings,
|
||||
Boots: pk.Boots,
|
||||
Body: pk.Body,
|
||||
}
|
||||
case *packet.PlayerArmourDamage:
|
||||
pks[pkIndex] = &legacypacket.PlayerArmourDamage{
|
||||
Bitset: pk.Bitset,
|
||||
HelmetDamage: pk.HelmetDamage,
|
||||
ChestplateDamage: pk.ChestplateDamage,
|
||||
LeggingsDamage: pk.LeggingsDamage,
|
||||
BootsDamage: pk.BootsDamage,
|
||||
BodyDamage: pk.BodyDamage,
|
||||
}
|
||||
case *packet.SetTitle:
|
||||
pks[pkIndex] = &legacypacket.SetTitle{
|
||||
ActionType: pk.ActionType,
|
||||
Text: pk.Text,
|
||||
FadeInDuration: pk.FadeInDuration,
|
||||
RemainDuration: pk.RemainDuration,
|
||||
FadeOutDuration: pk.FadeOutDuration,
|
||||
XUID: pk.XUID,
|
||||
PlatformOnlineID: pk.PlatformOnlineID,
|
||||
FilteredMessage: pk.FilteredMessage,
|
||||
}
|
||||
case *packet.StopSound:
|
||||
pks[pkIndex] = &legacypacket.StopSound{
|
||||
SoundName: pk.SoundName,
|
||||
StopAll: pk.StopAll,
|
||||
StopMusicLegacy: pk.StopMusicLegacy,
|
||||
}
|
||||
case *packet.InventoryTransaction:
|
||||
trData := pk.TransactionData
|
||||
if x, ok := trData.(*protocol.UseItemTransactionData); ok {
|
||||
trData = (&proto.UseItemTransactionData{}).FromLatest(x)
|
||||
}
|
||||
pks[pkIndex] = &legacypacket.InventoryTransaction{
|
||||
LegacyRequestID: pk.LegacyRequestID,
|
||||
LegacySetItemSlots: pk.LegacySetItemSlots,
|
||||
Actions: pk.Actions,
|
||||
TransactionData: trData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,6 +503,137 @@ func (p *Protocol) upgradePackets(pks []packet.Packet, conn *minecraft.Conn) []p
|
||||
Port: pk.Port,
|
||||
ReloadWorld: pk.ReloadWorld,
|
||||
}
|
||||
case *legacypacket.AddActor:
|
||||
links := make([]protocol.EntityLink, len(pk.EntityLinks))
|
||||
for i, l := range pk.EntityLinks {
|
||||
links[i] = l.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.AddActor{
|
||||
EntityUniqueID: pk.EntityUniqueID,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
EntityType: pk.EntityType,
|
||||
Position: pk.Position,
|
||||
Velocity: pk.Velocity,
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
HeadYaw: pk.HeadYaw,
|
||||
BodyYaw: pk.BodyYaw,
|
||||
Attributes: pk.Attributes,
|
||||
EntityMetadata: pk.EntityMetadata,
|
||||
EntityProperties: pk.EntityProperties,
|
||||
EntityLinks: links,
|
||||
}
|
||||
case *legacypacket.AddPlayer:
|
||||
links := make([]protocol.EntityLink, len(pk.EntityLinks))
|
||||
for i, l := range pk.EntityLinks {
|
||||
links[i] = l.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.AddPlayer{
|
||||
UUID: pk.UUID,
|
||||
Username: pk.Username,
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
PlatformChatID: pk.PlatformChatID,
|
||||
Position: pk.Position,
|
||||
Velocity: pk.Velocity,
|
||||
Pitch: pk.Pitch,
|
||||
Yaw: pk.Yaw,
|
||||
HeadYaw: pk.HeadYaw,
|
||||
HeldItem: pk.HeldItem,
|
||||
GameType: pk.GameType,
|
||||
EntityMetadata: pk.EntityMetadata,
|
||||
EntityProperties: pk.EntityProperties,
|
||||
AbilityData: pk.AbilityData,
|
||||
EntityLinks: links,
|
||||
DeviceID: pk.DeviceID,
|
||||
BuildPlatform: pk.BuildPlatform,
|
||||
}
|
||||
case *legacypacket.SetActorLink:
|
||||
pks[pkIndex] = &packet.SetActorLink{
|
||||
EntityLink: pk.EntityLink.ToLatest(),
|
||||
}
|
||||
case *legacypacket.CameraInstruction:
|
||||
pks[pkIndex] = &packet.CameraInstruction{
|
||||
Set: pk.Set,
|
||||
Clear: pk.Clear,
|
||||
Fade: pk.Fade,
|
||||
Target: pk.Target,
|
||||
RemoveTarget: pk.RemoveTarget,
|
||||
}
|
||||
case *legacypacket.ChangeDimension:
|
||||
pks[pkIndex] = &packet.ChangeDimension{
|
||||
Dimension: pk.Dimension,
|
||||
Position: pk.Position,
|
||||
Respawn: pk.Respawn,
|
||||
LoadingScreenID: pk.LoadingScreenID,
|
||||
}
|
||||
case *legacypacket.CorrectPlayerMovePrediction:
|
||||
pks[pkIndex] = &packet.CorrectPlayerMovePrediction{
|
||||
PredictionType: pk.PredictionType,
|
||||
Position: pk.Position,
|
||||
Delta: pk.Delta,
|
||||
Rotation: pk.Rotation,
|
||||
VehicleAngularVelocity: pk.VehicleAngularVelocity,
|
||||
OnGround: pk.OnGround,
|
||||
Tick: pk.Tick,
|
||||
}
|
||||
case *legacypacket.Disconnect:
|
||||
pks[pkIndex] = &packet.Disconnect{
|
||||
Reason: pk.Reason,
|
||||
HideDisconnectionScreen: pk.HideDisconnectionScreen,
|
||||
Message: pk.Message,
|
||||
FilteredMessage: pk.FilteredMessage,
|
||||
}
|
||||
case *legacypacket.EditorNetwork:
|
||||
pks[pkIndex] = &packet.EditorNetwork{
|
||||
RouteToManager: pk.RouteToManager,
|
||||
Payload: pk.Payload,
|
||||
}
|
||||
case *legacypacket.MobArmourEquipment:
|
||||
pks[pkIndex] = &packet.MobArmourEquipment{
|
||||
EntityRuntimeID: pk.EntityRuntimeID,
|
||||
Helmet: pk.Helmet,
|
||||
Chestplate: pk.Chestplate,
|
||||
Leggings: pk.Leggings,
|
||||
Boots: pk.Boots,
|
||||
Body: pk.Body,
|
||||
}
|
||||
case *legacypacket.PlayerArmourDamage:
|
||||
pks[pkIndex] = &packet.PlayerArmourDamage{
|
||||
Bitset: pk.Bitset,
|
||||
HelmetDamage: pk.HelmetDamage,
|
||||
ChestplateDamage: pk.ChestplateDamage,
|
||||
LeggingsDamage: pk.LeggingsDamage,
|
||||
BootsDamage: pk.BootsDamage,
|
||||
BodyDamage: pk.BodyDamage,
|
||||
}
|
||||
case *legacypacket.SetTitle:
|
||||
pks[pkIndex] = &packet.SetTitle{
|
||||
ActionType: pk.ActionType,
|
||||
Text: pk.Text,
|
||||
FadeInDuration: pk.FadeInDuration,
|
||||
RemainDuration: pk.RemainDuration,
|
||||
FadeOutDuration: pk.FadeOutDuration,
|
||||
XUID: pk.XUID,
|
||||
PlatformOnlineID: pk.PlatformOnlineID,
|
||||
FilteredMessage: pk.FilteredMessage,
|
||||
}
|
||||
case *legacypacket.StopSound:
|
||||
pks[pkIndex] = &packet.StopSound{
|
||||
SoundName: pk.SoundName,
|
||||
StopAll: pk.StopAll,
|
||||
StopMusicLegacy: pk.StopMusicLegacy,
|
||||
}
|
||||
case *legacypacket.InventoryTransaction:
|
||||
trData := pk.TransactionData
|
||||
if x, ok := trData.(*proto.UseItemTransactionData); ok {
|
||||
trData = x.ToLatest()
|
||||
}
|
||||
pks[pkIndex] = &packet.InventoryTransaction{
|
||||
LegacyRequestID: pk.LegacyRequestID,
|
||||
LegacySetItemSlots: pk.LegacySetItemSlots,
|
||||
Actions: pk.Actions,
|
||||
TransactionData: trData,
|
||||
}
|
||||
}
|
||||
}
|
||||
return pks
|
||||
|
||||
28
legacyver/v685.go
Normal file
28
legacyver/v685.go
Normal file
@@ -0,0 +1,28 @@
|
||||
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 (
|
||||
// ItemVersion685 ...
|
||||
ItemVersion685 = 191
|
||||
// BlockVersion685 ...
|
||||
BlockVersion685 int32 = (1 << 24) | (21 << 16) | (0 << 8)
|
||||
)
|
||||
|
||||
// New685 uses same data as 686
|
||||
func New685(direct bool) *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData686, requiredItemList686, ItemVersion685, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData686)
|
||||
|
||||
return &Protocol{
|
||||
ver: "1.21.0",
|
||||
id: proto.ID685,
|
||||
blockTranslator: NewBlockTranslator(blockMapping, latestBlockMapping, chunk.NewNetworkPersistentEncoding(blockMapping, BlockVersion685), chunk.NewBlockPaletteEncoding(blockMapping, BlockVersion685), false),
|
||||
itemTranslator: NewItemTranslator(itemMapping, itemMappingLatest, blockMapping, blockMappingLatest),
|
||||
}
|
||||
}
|
||||
36
legacyver/v686.go
Normal file
36
legacyver/v686.go
Normal 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 (
|
||||
// ItemVersion686 ...
|
||||
ItemVersion686 = 191
|
||||
// BlockVersion686 ...
|
||||
BlockVersion686 int32 = (1 << 24) | (21 << 16) | (2 << 8)
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed data/item_runtime_ids_686.nbt
|
||||
itemRuntimeIDData686 []byte
|
||||
//go:embed data/required_item_list_686.json
|
||||
requiredItemList686 []byte
|
||||
//go:embed data/block_states_686.nbt
|
||||
blockStateData686 []byte
|
||||
)
|
||||
|
||||
func New686(direct bool) *Protocol {
|
||||
itemMapping := mapping.NewItemMapping(itemRuntimeIDData686, requiredItemList686, ItemVersion686, false)
|
||||
blockMapping := mapping.NewBlockMapping(blockStateData686)
|
||||
|
||||
return &Protocol{
|
||||
ver: "1.21.2",
|
||||
id: proto.ID686,
|
||||
blockTranslator: NewBlockTranslator(blockMapping, latestBlockMapping, chunk.NewNetworkPersistentEncoding(blockMapping, BlockVersion686), chunk.NewBlockPaletteEncoding(blockMapping, BlockVersion686), false),
|
||||
itemTranslator: NewItemTranslator(itemMapping, itemMappingLatest, blockMapping, blockMappingLatest),
|
||||
}
|
||||
}
|
||||
4
main.go
4
main.go
@@ -29,6 +29,10 @@ func main() {
|
||||
StatusProvider: p,
|
||||
AcceptedProtocols: []minecraft.Protocol{
|
||||
legacyver.New748(false),
|
||||
legacyver.New729(false),
|
||||
legacyver.New712(false),
|
||||
legacyver.New686(false),
|
||||
legacyver.New685(false),
|
||||
},
|
||||
}.Listen("raknet", config.Connection.LocalAddress)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user