Skip to content

Commit

Permalink
minecraft/protocol: Support 1.21.50
Browse files Browse the repository at this point in the history
Co-authored-by: inotflying <[email protected]>
  • Loading branch information
TwistedAsylumMC and inotflying authored Dec 4, 2024
1 parent 268adeb commit e181313
Show file tree
Hide file tree
Showing 27 changed files with 352 additions and 51 deletions.
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

0 comments on commit e181313

Please sign in to comment.