Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minecraft/protocol: Support 1.21.50 #274

Merged
merged 9 commits into from
Dec 4, 2024
19 changes: 10 additions & 9 deletions minecraft/conn.go
Original file line number Diff line number Diff line change
Expand Up @@ -776,7 +776,7 @@ func (conn *Conn) handleClientToServerHandshake() error {
}
if pack.Encrypted() {
texturePack.ContentKey = pack.ContentKey()
texturePack.ContentIdentity = pack.Manifest().Header.UUID
texturePack.ContentIdentity = pack.Manifest().Header.UUID.String()
}
pk.TexturePacks = append(pk.TexturePacks, texturePack)
}
Expand Down Expand Up @@ -855,22 +855,23 @@ func (conn *Conn) handleResourcePacksInfo(pk *packet.ResourcePacksInfo) error {
packsToDownload := make([]string, 0, totalPacks)

for index, pack := range pk.TexturePacks {
if _, ok := conn.packQueue.downloadingPacks[pack.UUID]; ok {
id := pack.UUID.String()
if _, ok := conn.packQueue.downloadingPacks[id]; ok {
conn.log.Warn("handle ResourcePacksInfo: duplicate texture pack", "UUID", pack.UUID)
conn.packQueue.packAmount--
continue
}
if conn.downloadResourcePack != nil && !conn.downloadResourcePack(uuid.MustParse(pack.UUID), pack.Version, index, totalPacks) {
if conn.downloadResourcePack != nil && !conn.downloadResourcePack(uuid.MustParse(id), pack.Version, index, totalPacks) {
conn.ignoredResourcePacks = append(conn.ignoredResourcePacks, exemptedResourcePack{
uuid: pack.UUID,
uuid: id,
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{
packsToDownload = append(packsToDownload, id+"_"+pack.Version)
conn.packQueue.downloadingPacks[id] = downloadingPack{
size: pack.Size,
buf: bytes.NewBuffer(make([]byte, 0, pack.Size)),
newFrag: make(chan []byte),
Expand Down Expand Up @@ -939,7 +940,7 @@ func (conn *Conn) hasPack(uuid string, version string, hasBehaviours bool) bool
}
}
for _, pack := range conn.resourcePacks {
if pack.UUID() == uuid && pack.Version() == version && pack.HasBehaviours() == hasBehaviours {
if pack.UUID().String() == uuid && pack.Version() == version && pack.HasBehaviours() == hasBehaviours {
return true
}
}
Expand Down Expand Up @@ -971,7 +972,7 @@ func (conn *Conn) handleResourcePackClientResponse(pk *packet.ResourcePackClient
case packet.PackResponseAllPacksDownloaded:
pk := &packet.ResourcePackStack{BaseGameVersion: protocol.CurrentVersion, Experiments: []protocol.ExperimentData{{Name: "cameras", Enabled: true}}}
for _, pack := range conn.resourcePacks {
resourcePack := protocol.StackResourcePack{UUID: pack.UUID(), Version: pack.Version()}
resourcePack := protocol.StackResourcePack{UUID: pack.UUID().String(), Version: pack.Version()}
// If it has behaviours, add it to the behaviour pack list. If not, we add it to the texture packs
// list.
if pack.HasBehaviours() {
Expand Down Expand Up @@ -1158,7 +1159,7 @@ func (conn *Conn) handleResourcePackChunkData(pk *packet.ResourcePackChunkData)
// pack to be downloaded.
func (conn *Conn) handleResourcePackChunkRequest(pk *packet.ResourcePackChunkRequest) error {
current := conn.packQueue.currentPack
if current.UUID() != pk.UUID {
if current.UUID().String() != pk.UUID {
return fmt.Errorf("expected pack UUID %v, but got %v", current.UUID(), pk.UUID)
}
if conn.packQueue.currentOffset != uint64(pk.ChunkIndex)*packChunkSize {
Expand Down
2 changes: 1 addition & 1 deletion minecraft/listener.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (listener *Listener) AddResourcePack(pack *resource.Pack) {
func (listener *Listener) RemoveResourcePack(uuid string) {
listener.packsMu.Lock()
listener.packs = slices.DeleteFunc(listener.packs, func(pack *resource.Pack) bool {
return pack.UUID() == uuid
return pack.UUID().String() == uuid
})
listener.packsMu.Unlock()
}
Expand Down
43 changes: 43 additions & 0 deletions minecraft/protocol/bitset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package protocol

import "math/big"

// Bitset is a representation of std::bitset<size> being sent over the network, allowing for more than 64 bits
// to be stored in a single integer. A Bitset has a fixed size, which is set at creation time.
type Bitset struct {
size int
int *big.Int
}

// NewBitset creates a new Bitset with a specific size. The size is the amount of bits that the Bitset can
// store. Attempting to set a bit at an index higher than the size will panic.
func NewBitset(size int) Bitset {
return Bitset{size: size, int: new(big.Int)}
}

// Set sets a bit at a specific index in the Bitset. If the index is higher than the size of the Bitset, a
// panic will occur.
func (b Bitset) Set(i int) {
if i >= b.size {
panic("index out of bounds")
}
b.int.SetBit(b.int, i, 1)
}

// Unset unsets a bit at a specific index in the Bitset. If the index is higher than the size of the Bitset,
// a panic will occur.
func (b Bitset) Unset(i int) {
if i >= b.size {
panic("index out of bounds")
}
b.int.SetBit(b.int, i, 0)
}

// Load returns if a bit at a specific index in the Bitset is set. If the index is higher than the size of the
// Bitset, a panic will occur.
func (b Bitset) Load(i int) bool {
if i >= b.size {
panic("index out of bounds")
}
return b.int.Bit(i) == 1
}
148 changes: 147 additions & 1 deletion minecraft/protocol/camera.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import (
"image/color"
)

const (
AimAssistTargetModeAngle = iota
AimAssistTargetModeDistance
)

const (
AudioListenerCamera = iota
AudioListenerPlayer
Expand Down Expand Up @@ -163,8 +168,10 @@ type CameraPreset struct {
HorizontalRotationLimit Optional[mgl32.Vec2]
// VerticalRotationLimit is the vertical rotation limit of the camera.
VerticalRotationLimit Optional[mgl32.Vec2]
// ContinueTargeting determines whether the camera should continue targeting the entity or not.
// ContinueTargeting determines whether the camera should continue targeting when using aim assist.
ContinueTargeting Optional[bool]
// TrackingRadius is the radius around the camera that the aim assist should track targets.
TrackingRadius Optional[float32]
// 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]
Expand All @@ -181,6 +188,8 @@ type CameraPreset struct {
// AlignTargetAndCameraForward determines whether the camera should align the target and the camera forward
// or not.
AlignTargetAndCameraForward Optional[bool]
// AimAssist defines the aim assist to use when using this preset.
AimAssist Optional[CameraPresetAimAssist]
}

// Marshal encodes/decodes a CameraPreset.
Expand All @@ -197,10 +206,147 @@ func (x *CameraPreset) Marshal(r IO) {
OptionalFunc(r, &x.HorizontalRotationLimit, r.Vec2)
OptionalFunc(r, &x.VerticalRotationLimit, r.Vec2)
OptionalFunc(r, &x.ContinueTargeting, r.Bool)
OptionalFunc(r, &x.TrackingRadius, r.Float32)
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)
OptionalFunc(r, &x.AlignTargetAndCameraForward, r.Bool)
}

// CameraPresetAimAssist represents a preset for aim assist settings.
type CameraPresetAimAssist struct {
// Preset is the ID of the preset that has previously been defined in the CameraAimAssistPresets packet.
Preset Optional[string]
// TargetMode is the mode that the camera should use for detecting targets. This is one of the constants
// above.
TargetMode Optional[int32]
// Angle is the maximum angle around the playes's cursor that the aim assist should check for a target,
// if TargetMode is set to protocol.AimAssistTargetModeAngle.
Angle Optional[mgl32.Vec2]
// Distance is the maximum distance from the player's cursor should check for a target, if TargetMode is
// set to protocol.AimAssistTargetModeDistance.
Distance Optional[float32]
}

// Marshal encodes/decodes a CameraPresetAimAssist.
func (x *CameraPresetAimAssist) Marshal(r IO) {
OptionalFunc(r, &x.Preset, r.String)
OptionalFunc(r, &x.TargetMode, r.Int32)
OptionalFunc(r, &x.Angle, r.Vec2)
OptionalFunc(r, &x.Distance, r.Float32)
}

// CameraAimAssistCategoryGroup is a group of categories which can be used by a CameraAimAssistPreset.
type CameraAimAssistCategoryGroup struct {
// Identifier is the unique identifier of the group.
Identifier string
// Categories is a list of categories within this group.
Categories []CameraAimAssistCategory
}

// Marshal encodes/decodes a CameraAimAssistCategoryGroup.
func (x *CameraAimAssistCategoryGroup) Marshal(r IO) {
r.String(&x.Identifier)
Slice(r, &x.Categories)
}

// CameraAimAssistCategory is an aim assist category that defines priorities for specific blocks and entities.
type CameraAimAssistCategory struct {
// Name is the name of the category which can be used by a CameraAimAssistPreset.
Name string
// Priorities represents the block and entity specific priorities as well as the default priorities for
// this category.
Priorities CameraAimAssistPriorities
}

// Marshal encodes/decodes a CameraAimAssistCategory.
func (x *CameraAimAssistCategory) Marshal(r IO) {
r.String(&x.Name)
Single(r, &x.Priorities)
}

// CameraAimAssistPriorities represents the block and entity specific priorities for targetting. The aim
// assist will select the block or entity with the highest priority within the specified thresholds.
type CameraAimAssistPriorities struct {
// Entities is a list of priorities for specific entity identifiers.
Entities []CameraAimAssistPriority
// Blocks is a list of priorities for specific block identifiers.
Blocks []CameraAimAssistPriority
// EntityDefault is the default priority for entities.
EntityDefault Optional[int32]
// BlockDefault is the default priority for blocks.
BlockDefault Optional[int32]
}

// Marshal encodes/decodes a CameraAimAssistPriorities.
func (x *CameraAimAssistPriorities) Marshal(r IO) {
Slice(r, &x.Entities)
Slice(r, &x.Blocks)
OptionalFunc(r, &x.EntityDefault, r.Int32)
OptionalFunc(r, &x.BlockDefault, r.Int32)
}

// CameraAimAssistPriority represents a non-default priority for a specific target.
type CameraAimAssistPriority struct {
// Identifier is the identifier of a target to define the priority for.
Identifier string
// Priority is the priority for this specific target.
Priority int32
}

// Marshal encodes/decodes a CameraAimAssistPriority.
func (x *CameraAimAssistPriority) Marshal(r IO) {
r.String(&x.Identifier)
r.Int32(&x.Priority)
}

// CameraAimAssistPreset defines a base preset that can be extended upon when sending an aim assist.
type CameraAimAssistPreset struct {
// Identifier represents the identifier of this preset.
Identifier string
// CategoryGroup is the name of a CameraAimAssistCategoryGroup to use for the preset.
CategoryGroup string
// BlockExclusions is a list of block identifiers that should be ignored by the aim assist.
BlockExclusions []string
// LiquidTargets is a list of entity identifiers that should be targetted when inside of a liquid.
LiquidTargets []string
// ItemSettings is a list of settings for specific item identifiers. If an item is not listed here, it
// will fallback to DefaultItemSettings or HandSettings if no item is held.
ItemSettings []CameraAimAssistItemSettings
// DefaultItemSettings is the identifier of a category to use when the player is not holding an item
// listed in ItemSettings. This must be the identifier of a category within the
// CameraAimAssistCategoryGroup references by CategoryGroup.
DefaultItemSettings Optional[string]
// HandSettings is the identifier of a category to use when the player is not holding an item. This must
// be the identifier of a category within the CameraAimAssistCategoryGroup references by CategoryGroup.
HandSettings Optional[string]
}

// Marshal encodes/decodes a CameraAimAssistPreset.
func (x *CameraAimAssistPreset) Marshal(r IO) {
r.String(&x.Identifier)
r.String(&x.CategoryGroup)
FuncSlice(r, &x.BlockExclusions, r.String)
FuncSlice(r, &x.LiquidTargets, r.String)
Slice(r, &x.ItemSettings)
OptionalFunc(r, &x.DefaultItemSettings, r.String)
OptionalFunc(r, &x.HandSettings, r.String)
}

// CameraAimAssistItemSettings defines settings for how specific items should behave when using aim assist.
type CameraAimAssistItemSettings struct {
// Item is the identifier of the item to apply the settings to.
Item string
// Category is the identifier of a category to use which has been defined by a CameraAimAssistCategory.
// Only categories defined in the CameraAimAssistCategoryGroup used by the CameraAimAssistPreset can be
// used here.
Category string
}

// Marshal encodes/decodes a CameraAimAssistItemSettings.
func (x *CameraAimAssistItemSettings) Marshal(r IO) {
r.String(&x.Item)
r.String(&x.Category)
}
4 changes: 2 additions & 2 deletions minecraft/protocol/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package protocol

const (
// CurrentProtocol is the current protocol version for the version below.
CurrentProtocol = 748
CurrentProtocol = 766
// CurrentVersion is the current version of Minecraft as supported by the `packet` package.
CurrentVersion = "1.21.40"
CurrentVersion = "1.21.50"
)
1 change: 1 addition & 0 deletions minecraft/protocol/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type IO interface {
GameRule(x *GameRule)
AbilityValue(x *any)
CompressedBiomeDefinitions(x *map[string]any)
Bitset(x *Bitset, size int)

ShieldID() int32
UnknownEnumOption(value any, enum string)
Expand Down
4 changes: 4 additions & 0 deletions minecraft/protocol/item_stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,9 @@ type StackResponseSlotInfo struct {
StackNetworkID int32
// CustomName is the custom name of the item stack. It is used in relation to text filtering.
CustomName string
// FilteredCustomName is a filtered version of CustomName with all the profanity removed. The client will
// use this over CustomName if this field is not empty and they have the "Filter Profanity" setting enabled.
FilteredCustomName string
// DurabilityCorrection is the current durability of the item stack. This durability will be shown
// client-side after the response is sent to the client.
DurabilityCorrection int32
Expand All @@ -274,6 +277,7 @@ func (x *StackResponseSlotInfo) Marshal(r IO) {
r.InvalidValue(x.HotbarSlot, "hotbar slot", "hot bar slot must be equal to normal slot")
}
r.String(&x.CustomName)
r.String(&x.FilteredCustomName)
r.Varint32(&x.DurabilityCorrection)
}

Expand Down
1 change: 1 addition & 0 deletions minecraft/protocol/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
DeviceIOS
DeviceOSX
DeviceFireOS
// Deprecated: DeviceGearVR is deprecated as of 1.21.50.
DeviceGearVR
DeviceHololens
DeviceWin10
Expand Down
24 changes: 11 additions & 13 deletions minecraft/protocol/packet/camera_aim_assist.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,18 @@ const (
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.
// Preset is the ID of the preset that has previously been defined in the CameraAimAssistPresets packet.
Preset string
// Angle is the maximum angle around the playes's cursor that the aim assist should check for a target,
// if TargetMode is set to protocol.AimAssistTargetModeAngle.
Angle mgl32.Vec2
// Distance is the maximum distance from the player's cursor should check for a target, if TargetMode is
// set to protocol.AimAssistTargetModeDistance.
Distance float32
// TargetMode is the mode that the camera should use to aim at the target. This is one of the constants
// above.
// TargetMode is the mode that the camera should use for detecting targets. This is currently one of
// protocol.AimAssistTargetModeAngle or protocol.AimAssistTargetModeDistance.
TargetMode byte
// Action is the action that should be performed with the aim assist. This is one of the constants above.
Action byte
Expand All @@ -36,7 +33,8 @@ func (*CameraAimAssist) ID() uint32 {
}

func (pk *CameraAimAssist) Marshal(io protocol.IO) {
io.Vec2(&pk.ViewAngle)
io.String(&pk.Preset)
io.Vec2(&pk.Angle)
io.Float32(&pk.Distance)
io.Uint8(&pk.TargetMode)
io.Uint8(&pk.Action)
Expand Down
Loading
Loading