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

Implement 1.19 support #130

Merged
merged 8 commits into from Jun 7, 2022
20 changes: 10 additions & 10 deletions minecraft/protocol/command.go
Expand Up @@ -47,16 +47,16 @@ const (
CommandArgTypeValue = 4
CommandArgTypeWildcardInt = 5
CommandArgTypeOperator = 6
CommandArgTypeTarget = 7
CommandArgTypeWildcardTarget = 9
CommandArgTypeFilepath = 16
CommandArgTypeString = 38
CommandArgTypeBlockPosition = 46
CommandArgTypePosition = 47
CommandArgTypeMessage = 50
CommandArgTypeRawText = 52
CommandArgTypeJSON = 56
CommandArgTypeCommand = 69
CommandArgTypeTarget = 8
CommandArgTypeWildcardTarget = 10
CommandArgTypeFilepath = 17
CommandArgTypeString = 39
CommandArgTypeBlockPosition = 47
CommandArgTypePosition = 48
CommandArgTypeMessage = 51
CommandArgTypeRawText = 53
CommandArgTypeJSON = 57
CommandArgTypeCommand = 70
)
const (
// ParamOptionCollapseEnum specifies if the enum (only if the Type is actually an enum type. If not,
Expand Down
4 changes: 2 additions & 2 deletions minecraft/protocol/events.go
Expand Up @@ -228,7 +228,7 @@ func (a *AgentCommandEventData) Unmarshal(r *Reader) {
r.String(&a.Output)
}

// PatternRemovedEventData is the event data sent when a pattern is removed.
// PatternRemovedEventData is the event data sent when a pattern is removed. This is now deprecated.
type PatternRemovedEventData struct {
// ItemID ...
ItemID int32
Expand Down Expand Up @@ -346,7 +346,7 @@ func (m *MobBornEventData) Unmarshal(r *Reader) {
r.Uint8(&m.Colour)
}

// PetDiedEventData is the event data sent when a pet dies.
// PetDiedEventData is the event data sent when a pet dies. This is now deprecated.
type PetDiedEventData struct {
// KilledByOwner ...
KilledByOwner bool
Expand Down
4 changes: 2 additions & 2 deletions minecraft/protocol/info.go
Expand Up @@ -2,7 +2,7 @@ package protocol

const (
// CurrentProtocol is the current protocol version for the version below.
CurrentProtocol = 503
CurrentProtocol = 527
// CurrentVersion is the current version of Minecraft as supported by the `packet` package.
CurrentVersion = "1.18.30"
CurrentVersion = "1.19.0"
)
1 change: 1 addition & 0 deletions minecraft/protocol/os.go
Expand Up @@ -19,4 +19,5 @@ const (
DeviceNX
DeviceXBOX
DeviceWP
DeviceLinux
)
4 changes: 4 additions & 0 deletions minecraft/protocol/packet/id.go
Expand Up @@ -183,4 +183,8 @@ const (
IDDimensionData
IDAgentAction
IDChangeMobProperty
IDLessonProgress
IDRequestAbility
IDRequestPermissions
IDToastRequest
)
41 changes: 41 additions & 0 deletions minecraft/protocol/packet/lesson_progress.go
@@ -0,0 +1,41 @@
package packet

import (
"github.com/sandertv/gophertunnel/minecraft/protocol"
)

const (
LessonActionStart = iota
LessonActionComplete
LessonActionRestart
)

// LessonProgress is a packet sent by the server to the client to inform the client of updated progress on a lesson.
// This packet only functions on the Minecraft: Education Edition version of the game.
type LessonProgress struct {
// Identifier is the identifier of the lesson that is being progressed.
Identifier string
// Action is the action the client should perform to show progress. This is one of the constants defined above.
Action uint8
// Score is the score the client should use when displaying the progress.
Score int32
}

// ID ...
func (*LessonProgress) ID() uint32 {
return IDLessonProgress
}

// Marshal ...
func (pk *LessonProgress) Marshal(w *protocol.Writer) {
w.Uint8(&pk.Action)
w.Varint32(&pk.Score)
w.String(&pk.Identifier)
}

// Unmarshal ...
func (pk *LessonProgress) Unmarshal(r *protocol.Reader) {
r.Uint8(&pk.Action)
r.Varint32(&pk.Score)
r.String(&pk.Identifier)
}
1 change: 1 addition & 0 deletions minecraft/protocol/packet/level_event.go
Expand Up @@ -85,6 +85,7 @@ const (
LevelEventSculkCatalystBloom = 2036
LevelEventSculkCharge = 2037
LevelEventSculkChargePop = 2038
LevelEventSonicExplosion = 2039
LevelEventStartRaining = 3001
LevelEventStartThunderstorm = 3002
LevelEventStopRaining = 3003
Expand Down
20 changes: 19 additions & 1 deletion minecraft/protocol/packet/level_sound_event.go
Expand Up @@ -385,7 +385,7 @@ const (
SoundEventListening
SoundEventHeartbeat
SoundEventHornBreak
SoundEventSculkPlace
_
SoundEventSculkSpread
SoundEventSculkCharge
SoundEventSculkSensorPlace
Expand Down Expand Up @@ -430,6 +430,24 @@ const (
SoundEventGoatBass7
SoundEventGoatBass8
SoundEventGoatBass9
_
_
_
SoundEventImitateWarden
SoundEventListeningAngry
SoundEventItemGiven
SoundEventItemTaken
SoundEventDisappeared
SoundEventReappeared
_
SoundEventFrogspawnHatched
SoundEventLaySpawn
SoundEventFrogspawnBreak
SoundEventSonicBoom
SoundEventSonicCharge
SoundeventItemThrown
SoundEventRecord5
SoundEventConvertToFrog
SoundEventUndefined
)

Expand Down
5 changes: 5 additions & 0 deletions minecraft/protocol/packet/player_action.go
Expand Up @@ -16,6 +16,9 @@ type PlayerAction struct {
// BlockPosition is the position of the target block, if the action with the ActionType set concerned a
// block. If that is not the case, the block position will be zero.
BlockPosition protocol.BlockPos
// ResultPosition is the position of the action's result. When a UseItemOn action is sent, this is the position of
// the block clicked, but when a block is placed, this is the position at which the block will be placed.
ResultPosition protocol.BlockPos
JustTalDevelops marked this conversation as resolved.
Show resolved Hide resolved
// BlockFace is the face of the target block that was touched. If the action with the ActionType set
// concerned a block. If not, the face is always 0.
BlockFace int32
Expand All @@ -31,6 +34,7 @@ func (pk *PlayerAction) Marshal(w *protocol.Writer) {
w.Varuint64(&pk.EntityRuntimeID)
w.Varint32(&pk.ActionType)
w.UBlockPos(&pk.BlockPosition)
w.UBlockPos(&pk.ResultPosition)
w.Varint32(&pk.BlockFace)
}

Expand All @@ -39,5 +43,6 @@ func (pk *PlayerAction) Unmarshal(r *protocol.Reader) {
r.Varuint64(&pk.EntityRuntimeID)
r.Varint32(&pk.ActionType)
r.UBlockPos(&pk.BlockPosition)
r.UBlockPos(&pk.ResultPosition)
r.Varint32(&pk.BlockFace)
}
11 changes: 11 additions & 0 deletions minecraft/protocol/packet/player_auth_input.go
Expand Up @@ -65,6 +65,12 @@ const (
PlayModeNumModes
)

const (
InteractionModelTouch = iota
InteractionModelCrosshair
InteractionModelClassic
)

// PlayerAuthInput is sent by the client to allow for server authoritative movement. It is used to synchronise
// the player input with the position server-side.
// The client sends this packet when the ServerAuthoritativeMovementMode field in the StartGame packet is set
Expand All @@ -88,6 +94,9 @@ type PlayerAuthInput struct {
// PlayMode specifies the way that the player is playing. The values it holds, which are rather random,
// may be found above.
PlayMode uint32
// InteractionModel is a constant representing the interaction model the player is using. It is one of the
// constants that may be found above.
InteractionModel int32
// GazeDirection is the direction in which the player is gazing, when the PlayMode is PlayModeReality: In
// other words, when the player is playing in virtual reality.
GazeDirection mgl32.Vec3
Expand Down Expand Up @@ -120,6 +129,7 @@ func (pk *PlayerAuthInput) Marshal(w *protocol.Writer) {
w.Varuint64(&pk.InputData)
w.Varuint32(&pk.InputMode)
w.Varuint32(&pk.PlayMode)
w.Varint32(&pk.InteractionModel)
if pk.PlayMode == PlayModeReality {
w.Vec3(&pk.GazeDirection)
}
Expand Down Expand Up @@ -153,6 +163,7 @@ func (pk *PlayerAuthInput) Unmarshal(r *protocol.Reader) {
r.Varuint64(&pk.InputData)
r.Varuint32(&pk.InputMode)
r.Varuint32(&pk.PlayMode)
r.Varint32(&pk.InteractionModel)
if pk.PlayMode == PlayModeReality {
r.Vec3(&pk.GazeDirection)
}
Expand Down
4 changes: 4 additions & 0 deletions minecraft/protocol/packet/pool.go
Expand Up @@ -206,6 +206,10 @@ func init() {
IDDimensionData: func() Packet { return &DimensionData{} },
IDAgentAction: func() Packet { return &AgentAction{} },
IDChangeMobProperty: func() Packet { return &ChangeMobProperty{} },
IDLessonProgress: func() Packet { return &LessonProgress{} },
IDRequestAbility: func() Packet { return &RequestAbility{} },
IDRequestPermissions: func() Packet { return &RequestPermissions{} },
IDToastRequest: func() Packet { return &ToastRequest{} },
}
for id, pk := range packets {
Register(id, pk)
Expand Down
78 changes: 78 additions & 0 deletions minecraft/protocol/packet/request_ability.go
@@ -0,0 +1,78 @@
package packet

import (
"github.com/sandertv/gophertunnel/minecraft/protocol"
)

const (
AbilityBuild = iota
AbilityMine
AbilityDoorsAndSwitches
AbilityOpenContainers
AbilityAttackPlayers
AbilityAttackMobs
AbilityOperatorCommands
AbilityTeleport
AbilityInvulnerable
AbilityFlying
AbilityMayFly
AbilityInstantBuild
AbilityLightning
AbilityFlySpeed
AbilityWalkSpeed
AbilityMuted
AbilityWorldBuilder
AbilityNoClip
AbilityAbilityCount
)

// RequestAbility is a packet sent by the client to the server to request permission for a specific ability from the
// server. These abilities are defined above.
type RequestAbility struct {
// Ability is the ability that the client is requesting. This is one of the constants defined above.
Ability int32
// Value represents the value of the ability. This can either be a boolean or a float32, otherwise the writer/reader
// will panic.
Value any
}

// ID ...
func (*RequestAbility) ID() uint32 {
return IDRequestAbility
}

// Marshal ...
func (pk *RequestAbility) Marshal(w *protocol.Writer) {
w.Varint32(&pk.Ability)
switch val := pk.Value.(type) {
case bool:
valType, defaultVal := uint8(1), float32(0)
w.Uint8(&valType)
w.Bool(&val)
w.Float32(&defaultVal)
case float32:
valType, defaultVal := uint8(2), false
w.Uint8(&valType)
w.Bool(&defaultVal)
w.Float32(&val)
default:
w.InvalidValue(pk.Value, "ability value type", "must be bool or float32")
}
}

// Unmarshal ...
func (pk *RequestAbility) Unmarshal(r *protocol.Reader) {
valType, boolVal, floatVal := uint8(0), false, float32(0)
r.Varint32(&pk.Ability)
r.Uint8(&valType)
r.Bool(&boolVal)
r.Float32(&floatVal)
switch valType {
case 1:
pk.Value = boolVal
case 2:
pk.Value = floatVal
default:
r.InvalidValue(valType, "ability value type", "must be bool or float32")
}
}
37 changes: 37 additions & 0 deletions minecraft/protocol/packet/request_permissions.go
@@ -0,0 +1,37 @@
package packet

import (
"github.com/sandertv/gophertunnel/minecraft/protocol"
)

// RequestPermissions is a packet sent from the client to the server to request permissions that the client does not
// currently have. It can only be sent by operators and host in vanilla Minecraft.
type RequestPermissions struct {
// EntityUniqueID is the unique ID of the player. The unique ID is unique for the entire world and is
// often used in packets. Most servers send an EntityUniqueID equal to the EntityRuntimeID.
EntityUniqueID int64
// PermissionLevel is the current permission level of the player. This is one of the constants that may be found
// in the AdventureSettings packet.
PermissionLevel uint8
// RequestedPermissions contains the requested permission flags.
RequestedPermissions uint16
}

// ID ...
func (*RequestPermissions) ID() uint32 {
return IDRequestPermissions
}

// Marshal ...
func (pk *RequestPermissions) Marshal(w *protocol.Writer) {
w.Int64(&pk.EntityUniqueID)
w.Uint8(&pk.PermissionLevel)
w.Uint16(&pk.RequestedPermissions)
}

// Unmarshal ...
func (pk *RequestPermissions) Unmarshal(r *protocol.Reader) {
r.Int64(&pk.EntityUniqueID)
r.Uint8(&pk.PermissionLevel)
r.Uint16(&pk.RequestedPermissions)
}
12 changes: 12 additions & 0 deletions minecraft/protocol/packet/start_game.go
Expand Up @@ -2,6 +2,8 @@ package packet

import (
"github.com/go-gl/mathgl/mgl32"
"github.com/google/uuid"
"github.com/sandertv/gophertunnel/minecraft/nbt"
"github.com/sandertv/gophertunnel/minecraft/protocol"
)

Expand Down Expand Up @@ -194,9 +196,15 @@ type StartGame struct {
ServerAuthoritativeInventory bool
// GameVersion is the version of the game the server is running. The exact function of this field isn't clear.
GameVersion string
// PropertyData contains properties that should be applied on the player. These properties are the same as the
// ones that are sent in the SyncActorProperty packet.
PropertyData map[string]any
// ServerBlockStateChecksum is a checksum to ensure block states between the server and client match.
// This can simply be left empty, and the client will avoid trying to verify it.
ServerBlockStateChecksum uint64
// WorldTemplateID is a UUID that identifies the template that was used to generate the world. Servers that do not
// use a world based off of a template can set this to an empty UUID.
WorldTemplateID uuid.UUID
}

// ID ...
Expand Down Expand Up @@ -285,7 +293,9 @@ func (pk *StartGame) Marshal(w *protocol.Writer) {
w.String(&pk.MultiPlayerCorrelationID)
w.Bool(&pk.ServerAuthoritativeInventory)
w.String(&pk.GameVersion)
w.NBT(&pk.PropertyData, nbt.NetworkLittleEndian)
w.Uint64(&pk.ServerBlockStateChecksum)
w.UUID(&pk.WorldTemplateID)
}

// Unmarshal ...
Expand Down Expand Up @@ -371,5 +381,7 @@ func (pk *StartGame) Unmarshal(r *protocol.Reader) {
r.String(&pk.MultiPlayerCorrelationID)
r.Bool(&pk.ServerAuthoritativeInventory)
r.String(&pk.GameVersion)
r.NBT(&pk.PropertyData, nbt.NetworkLittleEndian)
r.Uint64(&pk.ServerBlockStateChecksum)
r.UUID(&pk.WorldTemplateID)
}