diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index fa015abc..00000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -patreon: sandertv \ No newline at end of file diff --git a/minecraft/conn.go b/minecraft/conn.go index b0806cf9..4ced467a 100644 --- a/minecraft/conn.go +++ b/minecraft/conn.go @@ -808,19 +808,6 @@ func (conn *Conn) handleClientToServerHandshake() error { URL: pack.DownloadURL(), }) } - - // If it has behaviours, add it to the behaviour pack list. If not, we add it to the texture packs - // list. - if pack.HasBehaviours() { - behaviourPack := protocol.BehaviourPackInfo{UUID: pack.UUID(), Version: pack.Version(), Size: uint64(pack.Len())} - if pack.HasScripts() { - // One of the resource packs has scripts, so we set HasScripts in the packet to true. - pk.HasScripts = true - behaviourPack.HasScripts = true - } - pk.BehaviourPacks = append(pk.BehaviourPacks, behaviourPack) - continue - } texturePack := protocol.TexturePackInfo{UUID: pack.UUID(), Version: pack.Version(), Size: uint64(pack.Len())} if pack.Encrypted() { texturePack.ContentKey = pack.ContentKey() @@ -894,7 +881,7 @@ func (conn *Conn) handleClientCacheStatus(pk *packet.ClientCacheStatus) error { func (conn *Conn) handleResourcePacksInfo(pk *packet.ResourcePacksInfo) error { // First create a new resource pack queue with the information in the packet so we can download them // properly later. - totalPacks := len(pk.TexturePacks) + len(pk.BehaviourPacks) + totalPacks := len(pk.TexturePacks) conn.packQueue = &resourcePackQueue{ packAmount: totalPacks, downloadingPacks: make(map[string]downloadingPack), @@ -925,29 +912,6 @@ func (conn *Conn) handleResourcePacksInfo(pk *packet.ResourcePacksInfo) error { contentKey: pack.ContentKey, } } - for index, pack := range pk.BehaviourPacks { - if _, ok := conn.packQueue.downloadingPacks[pack.UUID]; ok { - conn.log.Printf("handle ResourcePacksInfo: duplicate behaviour pack (UUID=%v)\n", pack.UUID) - conn.packQueue.packAmount-- - continue - } - if conn.downloadResourcePack != nil && !conn.downloadResourcePack(uuid.MustParse(pack.UUID), pack.Version, index, totalPacks) { - conn.ignoredResourcePacks = append(conn.ignoredResourcePacks, exemptedResourcePack{ - uuid: pack.UUID, - version: pack.Version, - }) - conn.packQueue.packAmount-- - continue - } - // This UUID_Version is a hack Mojang put in place. - packsToDownload = append(packsToDownload, pack.UUID+"_"+pack.Version) - conn.packQueue.downloadingPacks[pack.UUID] = downloadingPack{ - size: pack.Size, - buf: bytes.NewBuffer(make([]byte, 0, pack.Size)), - newFrag: make(chan []byte), - contentKey: pack.ContentKey, - } - } if len(packsToDownload) != 0 { conn.expect(packet.IDResourcePackDataInfo, packet.IDResourcePackChunkData) diff --git a/minecraft/protocol/attribute.go b/minecraft/protocol/attribute.go index 73a2f0d0..549b0447 100644 --- a/minecraft/protocol/attribute.go +++ b/minecraft/protocol/attribute.go @@ -39,6 +39,12 @@ func (x *AttributeValue) Marshal(r IO) { // holds a default value, maximum and minimum value, name and its current value. type Attribute struct { 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 @@ -51,6 +57,8 @@ func (x *Attribute) Marshal(r IO) { r.Float32(&x.Min) r.Float32(&x.Max) r.Float32(&x.Value) + r.Float32(&x.DefaultMin) + r.Float32(&x.DefaultMax) r.Float32(&x.Default) r.String(&x.Name) Slice(r, &x.Modifiers) diff --git a/minecraft/protocol/camera.go b/minecraft/protocol/camera.go index 06f327d5..19233144 100644 --- a/minecraft/protocol/camera.go +++ b/minecraft/protocol/camera.go @@ -152,9 +152,15 @@ type CameraPreset struct { RotX Optional[float32] // RotY is the default yaw of the camera. RotY Optional[float32] + // RotationSpeed is the speed at which the camera should rotate. + RotationSpeed Optional[float32] + // SnapToTarget determines whether the camera should snap to the target entity or not. + SnapToTarget Optional[bool] // ViewOffset is only used in a follow_orbit camera and controls an offset based on a pivot point to the // player, causing it to be shifted in a certain direction. ViewOffset Optional[mgl32.Vec2] + // EntityOffset controls the offset from the entity that the camera should be rendered at. + EntityOffset Optional[mgl32.Vec3] // Radius is only used in a follow_orbit camera and controls how far away from the player the camera should // be rendered. Radius Optional[float32] @@ -174,7 +180,10 @@ func (x *CameraPreset) Marshal(r IO) { OptionalFunc(r, &x.PosZ, r.Float32) OptionalFunc(r, &x.RotX, r.Float32) OptionalFunc(r, &x.RotY, r.Float32) + OptionalFunc(r, &x.RotationSpeed, r.Float32) + OptionalFunc(r, &x.SnapToTarget, r.Bool) OptionalFunc(r, &x.ViewOffset, r.Vec2) + OptionalFunc(r, &x.EntityOffset, r.Vec3) OptionalFunc(r, &x.Radius, r.Float32) OptionalFunc(r, &x.AudioListener, r.Uint8) OptionalFunc(r, &x.PlayerEffects, r.Bool) diff --git a/minecraft/protocol/container.go b/minecraft/protocol/container.go index d9a36991..e3c063d8 100644 --- a/minecraft/protocol/container.go +++ b/minecraft/protocol/container.go @@ -112,12 +112,12 @@ const ( 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 is - // set to 0. - DynamicContainerID uint32 + // 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 Optional[uint32] } func (x *FullContainerName) Marshal(r IO) { r.Uint8(&x.ContainerID) - r.Uint32(&x.DynamicContainerID) + OptionalFunc(r, &x.DynamicContainerID, r.Uint32) } diff --git a/minecraft/protocol/info.go b/minecraft/protocol/info.go index 652fcd2e..e1f3fc47 100644 --- a/minecraft/protocol/info.go +++ b/minecraft/protocol/info.go @@ -2,7 +2,7 @@ package protocol const ( // CurrentProtocol is the current protocol version for the version below. - CurrentProtocol = 712 + CurrentProtocol = 729 // CurrentVersion is the current version of Minecraft as supported by the `packet` package. - CurrentVersion = "1.21.20" + CurrentVersion = "1.21.30" ) diff --git a/minecraft/protocol/packet/camera_aim_assist.go b/minecraft/protocol/packet/camera_aim_assist.go new file mode 100644 index 00000000..c0898f34 --- /dev/null +++ b/minecraft/protocol/packet/camera_aim_assist.go @@ -0,0 +1,43 @@ +package packet + +import ( + "github.com/go-gl/mathgl/mgl32" + "github.com/sandertv/gophertunnel/minecraft/protocol" +) + +const ( + CameraAimAssistActionSet = iota + CameraAimAssistActionClear +) + +const ( + CameraAimAssistTargetModeAngle = iota + CameraAimAssistTargetModeDistance +) + +// CameraAimAssist is sent by the server to the client to set up aim assist for the client's camera. +type CameraAimAssist struct { + // ViewAngle is the angle that the camera should aim at, if TargetMode is set to + // CameraAimAssistTargetModeAngle. + ViewAngle mgl32.Vec2 + // Distance is the distance that the camera should keep from the target, if TargetMode is set to + // CameraAimAssistTargetModeDistance. + Distance float32 + // TargetMode is the mode that the camera should use to aim at the target. This is one of the constants + // above. + TargetMode byte + // Action is the action that should be performed with the aim assist. This is one of the constants above. + Action byte +} + +// ID ... +func (*CameraAimAssist) ID() uint32 { + return IDCameraAimAssist +} + +func (pk *CameraAimAssist) Marshal(io protocol.IO) { + io.Vec2(&pk.ViewAngle) + io.Float32(&pk.Distance) + io.Uint8(&pk.TargetMode) + io.Uint8(&pk.Action) +} diff --git a/minecraft/protocol/packet/container_registry_cleanup.go b/minecraft/protocol/packet/container_registry_cleanup.go new file mode 100644 index 00000000..babcabc2 --- /dev/null +++ b/minecraft/protocol/packet/container_registry_cleanup.go @@ -0,0 +1,22 @@ +package packet + +import ( + "github.com/sandertv/gophertunnel/minecraft/protocol" +) + +// 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 []protocol.FullContainerName +} + +// ID ... +func (*ContainerRegistryCleanup) ID() uint32 { + return IDContainerRegistryCleanup +} + +func (pk *ContainerRegistryCleanup) Marshal(io protocol.IO) { + protocol.Slice(io, &pk.RemovedContainers) +} diff --git a/minecraft/protocol/packet/emote.go b/minecraft/protocol/packet/emote.go index cfc3a38e..fe0f5b6e 100644 --- a/minecraft/protocol/packet/emote.go +++ b/minecraft/protocol/packet/emote.go @@ -15,6 +15,8 @@ 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 @@ -36,6 +38,7 @@ func (*Emote) ID() uint32 { func (pk *Emote) Marshal(io protocol.IO) { io.Varuint64(&pk.EntityRuntimeID) io.String(&pk.EmoteID) + io.Varuint32(&pk.EmoteLength) io.String(&pk.XUID) io.String(&pk.PlatformID) io.Uint8(&pk.Flags) diff --git a/minecraft/protocol/packet/id.go b/minecraft/protocol/packet/id.go index ef63df5b..92f98689 100644 --- a/minecraft/protocol/packet/id.go +++ b/minecraft/protocol/packet/id.go @@ -216,4 +216,6 @@ const ( IDJigsawStructureData IDCurrentStructureFeature IDServerBoundDiagnostics + IDCameraAimAssist + IDContainerRegistryCleanup ) diff --git a/minecraft/protocol/packet/inventory_content.go b/minecraft/protocol/packet/inventory_content.go index 49503663..09bef7a2 100644 --- a/minecraft/protocol/packet/inventory_content.go +++ b/minecraft/protocol/packet/inventory_content.go @@ -14,9 +14,10 @@ type InventoryContent struct { // Content is the new content of the inventory. The length of this slice must be equal to the full size of // the inventory window updated. Content []protocol.ItemInstance - // DynamicWindowID is the ID of the window if it is dynamic. If the window is not dynamic, this field is - // set to 0. - DynamicWindowID uint32 + // Container is the protocol.FullContainerName that describes the container that the content is for. + Container protocol.FullContainerName + // DynamicContainerSize is the size of the container, if the container is dynamic. + DynamicContainerSize uint32 } // ID ... @@ -27,5 +28,6 @@ func (*InventoryContent) ID() uint32 { func (pk *InventoryContent) Marshal(io protocol.IO) { io.Varuint32(&pk.WindowID) protocol.FuncSlice(io, &pk.Content, io.ItemInstance) - io.Varuint32(&pk.DynamicWindowID) + protocol.Single(io, &pk.Container) + io.Varuint32(&pk.DynamicContainerSize) } diff --git a/minecraft/protocol/packet/inventory_slot.go b/minecraft/protocol/packet/inventory_slot.go index 8e368825..421c86ae 100644 --- a/minecraft/protocol/packet/inventory_slot.go +++ b/minecraft/protocol/packet/inventory_slot.go @@ -14,9 +14,10 @@ type InventorySlot struct { // Slot is the index of the slot that the packet modifies. The new item will be set to the slot at this // index. Slot uint32 - // DynamicWindowID is the ID of the window if it is dynamic. If the window is not dynamic, this field is - // set to 0. - DynamicWindowID uint32 + // Container is the protocol.FullContainerName that describes the container that the content is for. + Container protocol.FullContainerName + // DynamicContainerSize is the size of the container, if the container is dynamic. + DynamicContainerSize uint32 // NewItem is the item to be put in the slot at Slot. It will overwrite any item that may currently // be present in that slot. NewItem protocol.ItemInstance @@ -30,6 +31,7 @@ func (*InventorySlot) ID() uint32 { func (pk *InventorySlot) Marshal(io protocol.IO) { io.Varuint32(&pk.WindowID) io.Varuint32(&pk.Slot) - io.Varuint32(&pk.DynamicWindowID) + protocol.Single(io, &pk.Container) + io.Varuint32(&pk.DynamicContainerSize) io.ItemInstance(&pk.NewItem) } diff --git a/minecraft/protocol/packet/level_sound_event.go b/minecraft/protocol/packet/level_sound_event.go index 93de43bf..d19c01c3 100644 --- a/minecraft/protocol/packet/level_sound_event.go +++ b/minecraft/protocol/packet/level_sound_event.go @@ -538,6 +538,8 @@ const ( SoundEventRecordCreatorMusicBox SoundEventRecordPrecipice SoundEventVaultRejectRewardedPlayer + SoundEventImitateDrowned + SoundEventBundleInsertFailed ) // LevelSoundEvent is sent by the server to make any kind of built-in sound heard to a player. It is sent to, diff --git a/minecraft/protocol/packet/player_auth_input.go b/minecraft/protocol/packet/player_auth_input.go index 4a2a5732..c4470fe5 100644 --- a/minecraft/protocol/packet/player_auth_input.go +++ b/minecraft/protocol/packet/player_auth_input.go @@ -55,6 +55,10 @@ const ( InputFlagPaddlingLeft InputFlagPaddlingRight InputFlagBlockBreakingDelayEnabled + InputFlagHorizontalCollision + InputFlagVerticalCollision + InputFlagDownLeft + InputFlagDownRight ) const ( diff --git a/minecraft/protocol/packet/pool.go b/minecraft/protocol/packet/pool.go index 6e0b01f9..78620a2f 100644 --- a/minecraft/protocol/packet/pool.go +++ b/minecraft/protocol/packet/pool.go @@ -256,6 +256,8 @@ func init() { IDJigsawStructureData: func() Packet { return &JigsawStructureData{} }, IDCurrentStructureFeature: func() Packet { return &CurrentStructureFeature{} }, IDServerBoundDiagnostics: func() Packet { return &ServerBoundDiagnostics{} }, + IDCameraAimAssist: func() Packet { return &CameraAimAssist{} }, + IDContainerRegistryCleanup: func() Packet { return &ContainerRegistryCleanup{} }, } for id, pk := range serverOriginating { RegisterPacketFromServer(id, pk) diff --git a/minecraft/protocol/packet/resource_packs_info.go b/minecraft/protocol/packet/resource_packs_info.go index 65b4ed3c..effc41b2 100644 --- a/minecraft/protocol/packet/resource_packs_info.go +++ b/minecraft/protocol/packet/resource_packs_info.go @@ -17,15 +17,10 @@ type ResourcePacksInfo struct { // HasScripts specifies if any of the resource packs contain scripts in them. If set to true, only clients // that support scripts will be able to download them. HasScripts bool - // BehaviourPack is a list of behaviour packs that the client needs to download before joining the server. - // All of these behaviour packs will be applied together. - BehaviourPacks []protocol.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. TexturePacks []protocol.TexturePackInfo - // ForcingServerPacks is currently an unclear field. - ForcingServerPacks bool // PackURLs is a list of URLs that the client can use to download a resource pack instead of downloading // it the usual way. PackURLs []protocol.PackURL @@ -40,8 +35,6 @@ func (pk *ResourcePacksInfo) Marshal(io protocol.IO) { io.Bool(&pk.TexturePackRequired) io.Bool(&pk.HasAddons) io.Bool(&pk.HasScripts) - io.Bool(&pk.ForcingServerPacks) - protocol.SliceUint16Length(io, &pk.BehaviourPacks) protocol.SliceUint16Length(io, &pk.TexturePacks) protocol.Slice(io, &pk.PackURLs) } diff --git a/minecraft/protocol/packet/transfer.go b/minecraft/protocol/packet/transfer.go index ca773d54..2c54939a 100644 --- a/minecraft/protocol/packet/transfer.go +++ b/minecraft/protocol/packet/transfer.go @@ -11,6 +11,8 @@ type Transfer struct { Address string // Port is the UDP port of the new server. Port uint16 + // ReloadWorld currently has an unknown usage. + ReloadWorld bool } // ID ... @@ -21,4 +23,5 @@ func (*Transfer) ID() uint32 { func (pk *Transfer) Marshal(io protocol.IO) { io.String(&pk.Address) io.Uint16(&pk.Port) + io.Bool(&pk.ReloadWorld) } diff --git a/minecraft/protocol/resource_pack.go b/minecraft/protocol/resource_pack.go index 753f3353..24581faa 100644 --- a/minecraft/protocol/resource_pack.go +++ b/minecraft/protocol/resource_pack.go @@ -1,44 +1,5 @@ package protocol -// 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 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) -} - // TexturePackInfo represents a texture pack's info sent over network. It holds information about the // texture pack such as its name, description and version. type TexturePackInfo struct {