Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions anticheat/game/movement.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ const (
BedBounceMultiplier = float32(-0.66)
// This can be validated in Mob::ascendLadder()
ClimbSpeed = float32(0.2)
MaxConsumingImpulse = float32(0.1225)
MaxSneakImpulse = float32(0.3)
MaxNormalizedImpulse = float32(0.70710678118) // 1/sqrt(2)

DefaultPlayerHeightOffset = float32(1.62)
Expand Down
2 changes: 1 addition & 1 deletion anticheat/integration/proxy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import (
"log/slog"
"time"

proxycore "github.com/oomph-ac/oomph/transferproxy"
"github.com/oomph-ac/oomph/anticheat/player"
"github.com/oomph-ac/oomph/anticheat/player/component"
playercontext "github.com/oomph-ac/oomph/anticheat/player/context"
"github.com/oomph-ac/oomph/anticheat/player/detection"
proxycore "github.com/oomph-ac/oomph/transferproxy"
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
Expand Down
12 changes: 10 additions & 2 deletions anticheat/player/component/acknowledgement/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
type UpdateBlockBatch struct {
mPlayer *player.Player
updates map[df_cube.Pos]uint32
layer uint8

expiresIn int64
valid bool
Expand All @@ -19,6 +20,11 @@ func NewUpdateBlockBatchACK(p *player.Player) *UpdateBlockBatch {
return &UpdateBlockBatch{mPlayer: p, updates: make(map[df_cube.Pos]uint32), valid: true}
}

// NewLayerUpdateBlockBatchACK creates a block update batch for a non-primary Bedrock storage layer.
func NewLayerUpdateBlockBatchACK(p *player.Player, layer uint8) *UpdateBlockBatch {
return &UpdateBlockBatch{mPlayer: p, updates: make(map[df_cube.Pos]uint32), layer: layer, valid: true}
}

func (ack *UpdateBlockBatch) Blocks() map[df_cube.Pos]uint32 {
return ack.updates
}
Expand Down Expand Up @@ -50,8 +56,10 @@ func (ack *UpdateBlockBatch) Run() {
ack.mPlayer.Log().Warn("unable to find block with runtime ID", "blockRuntimeID", bRuntimeID)
b = block.Air{}
}
ack.mPlayer.World().SetBlock(pos, b, nil)
ack.mPlayer.WorldUpdater().RemovePendingUpdate(pos, bRuntimeID)
ack.mPlayer.World().SetBlockLayer(pos, b, ack.layer)
if ack.layer == 0 {
ack.mPlayer.WorldUpdater().RemovePendingUpdate(pos, bRuntimeID)
}
}
ack.updates = nil
}
Expand Down
5 changes: 5 additions & 0 deletions anticheat/player/component/acknowledgement/movement.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ func (ack *UpdateAttributes) Run() {
case "minecraft:movement":
ack.mPlayer.Movement().SetMovementSpeed(attribute.Value)
ack.mPlayer.Movement().SetDefaultMovementSpeed(attribute.Default)
case "minecraft:underwater_movement":
ack.mPlayer.Movement().SetUnderwaterMovementSpeed(attribute.Value)
case "minecraft:lava_movement":
ack.mPlayer.Movement().SetLavaMovementSpeed(attribute.Value)
case "minecraft:health":
ack.mPlayer.Alive = attribute.Value > 0
case "minecraft:player.hunger":
Expand Down Expand Up @@ -165,6 +169,7 @@ func (ack *PlayerUpdateActorData) Run() {
ack.mPlayer.Movement().SetImmobile(utils.HasDataFlag(entity.DataFlagImmobile, flags))
ack.mPlayer.Movement().SetServerSprint(utils.HasDataFlag(entity.DataFlagSprinting, flags))
ack.mPlayer.Movement().SetHasGravity(utils.HasDataFlag(entity.DataFlagAffectedByGravity, flags))
ack.mPlayer.Movement().SetSwimming(utils.HasDataFlag(entity.DataFlagSwimming, flags))

if !utils.HasDataFlag(entity.DataFlagAction, flags) && ack.mPlayer.StartUseConsumableTick != 0 {
ack.mPlayer.StartUseConsumableTick = 0
Expand Down
182 changes: 159 additions & 23 deletions anticheat/player/component/movement.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,10 +89,14 @@ type AuthoritativeMovementComponent struct {
jumpHeight float32
fallDistance float32

movementSpeed float32
defaultMovementSpeed float32
airSpeed float32
serverUpdatedSpeed bool
movementSpeed float32
defaultMovementSpeed float32
airSpeed float32
underwaterMovementSpeed float32
lavaMovementSpeed float32
swimSpeedMultiplier float32
dolphinBoostTicks int64
serverUpdatedSpeed bool

knockback mgl32.Vec3
ticksSinceKb uint64
Expand All @@ -109,9 +113,14 @@ type AuthoritativeMovementComponent struct {
serverSprint, serverSprintApplied bool

sneaking, pressingSneak bool
swimming bool
swimAmount float32
autoJumpingInWater bool
wantDown bool
wantDownSlow bool

jumping, pressingJump bool
jumpDelay uint64
jumping, pressingJump, effectiveJumping bool
jumpDelay uint64

collideX, collideY, collideZ bool
onGround bool
Expand All @@ -138,10 +147,13 @@ type AuthoritativeMovementComponent struct {

func NewAuthoritativeMovementComponent(p *player.Player) *AuthoritativeMovementComponent {
return &AuthoritativeMovementComponent{
mPlayer: p,
nonAuthoritative: &NonAuthoritativeMovement{},
defaultMovementSpeed: 0.1,
airSpeed: 0.02,
mPlayer: p,
nonAuthoritative: &NonAuthoritativeMovement{},
defaultMovementSpeed: 0.1,
airSpeed: 0.02,
underwaterMovementSpeed: 0.02,
lavaMovementSpeed: 0.02,
swimSpeedMultiplier: 1,
}
}

Expand Down Expand Up @@ -327,6 +339,11 @@ func (mc *AuthoritativeMovementComponent) PressingJump() bool {
return mc.pressingJump
}

// EffectiveJumping returns the jumping state produced by continuous jump, automatic liquid jump, or block ascent input.
func (mc *AuthoritativeMovementComponent) EffectiveJumping() bool {
return mc.effectiveJumping
}

// JumpDelay returns the number of ticks until the movement component can make another jump.
func (mc *AuthoritativeMovementComponent) JumpDelay() uint64 {
return mc.jumpDelay
Expand All @@ -352,6 +369,36 @@ func (mc *AuthoritativeMovementComponent) SetPressingSneak(pressing bool) {
mc.pressingSneak = pressing
}

// Swimming returns whether the client is using the swimming movement pose.
func (mc *AuthoritativeMovementComponent) Swimming() bool {
return mc.swimming
}

// SetSwimming sets whether the movement component is using the swimming movement pose.
func (mc *AuthoritativeMovementComponent) SetSwimming(swimming bool) {
mc.swimming = swimming
}

// SwimAmount returns the client swim-pose interpolation amount.
func (mc *AuthoritativeMovementComponent) SwimAmount() float32 {
return mc.swimAmount
}

// AutoJumpingInWater returns whether the client is automatically swimming upward.
func (mc *AuthoritativeMovementComponent) AutoJumpingInWater() bool {
return mc.autoJumpingInWater
}

// WantDown returns whether the client requested downward movement.
func (mc *AuthoritativeMovementComponent) WantDown() bool {
return mc.wantDown
}

// WantDownSlow returns whether the client requested the slow downward swim input.
func (mc *AuthoritativeMovementComponent) WantDownSlow() bool {
return mc.wantDownSlow
}

// PenetratedLastFrame returns true if the movement component had penetrated through a block in
// the previous simulation frame.
func (mc *AuthoritativeMovementComponent) PenetratedLastFrame() bool {
Expand Down Expand Up @@ -467,6 +514,9 @@ func (mc *AuthoritativeMovementComponent) BoundingBox() cube.BBox {
scale := mc.size[2]
width := (mc.size[0] * 0.5) * scale
height := mc.size[1] * scale
if mc.swimming {
height = mc.size[0] * scale
}
var yOffset float32
if mc.mPlayer.VersionInRange(-1, player.GameVersion1_20_60) {
yOffset = mc.slideOffset.Y()
Expand All @@ -485,6 +535,10 @@ func (mc *AuthoritativeMovementComponent) BoundingBox() cube.BBox {
// ClientBoundingBox returns the bounding box of the movement component translated to the client's position.
func (mc *AuthoritativeMovementComponent) ClientBoundingBox() cube.BBox {
width := mc.size[0] / 2
height := mc.size[1]
if mc.swimming {
height = mc.size[0]
}
var yOffset float32
if mc.mPlayer.VersionInRange(-1, player.GameVersion1_20_60) {
yOffset = mc.slideOffset.Y()
Expand All @@ -495,7 +549,7 @@ func (mc *AuthoritativeMovementComponent) ClientBoundingBox() cube.BBox {
mc.nonAuthoritative.pos[1]+yOffset,
mc.nonAuthoritative.pos[2]-width,
mc.nonAuthoritative.pos[0]+width,
mc.nonAuthoritative.pos[1]+mc.size[1]+yOffset,
mc.nonAuthoritative.pos[1]+height+yOffset,
mc.nonAuthoritative.pos[2]+width,
).GrowVec3(mgl32.Vec3{-1e-4, 0, -1e-4})
}
Expand Down Expand Up @@ -571,6 +625,36 @@ func (mc *AuthoritativeMovementComponent) SetAirSpeed(newSpeed float32) {
mc.airSpeed = newSpeed
}

// UnderwaterMovementSpeed returns the base relative acceleration in water.
func (mc *AuthoritativeMovementComponent) UnderwaterMovementSpeed() float32 {
return mc.underwaterMovementSpeed
}

// SetUnderwaterMovementSpeed sets the base relative acceleration in water.
func (mc *AuthoritativeMovementComponent) SetUnderwaterMovementSpeed(speed float32) {
mc.underwaterMovementSpeed = speed
}

// LavaMovementSpeed returns the base relative acceleration in lava.
func (mc *AuthoritativeMovementComponent) LavaMovementSpeed() float32 {
return mc.lavaMovementSpeed
}

// SetLavaMovementSpeed sets the base relative acceleration in lava.
func (mc *AuthoritativeMovementComponent) SetLavaMovementSpeed(speed float32) {
mc.lavaMovementSpeed = speed
}

// SwimSpeedMultiplier returns the transient water-speed multiplier.
func (mc *AuthoritativeMovementComponent) SwimSpeedMultiplier() float32 {
return mc.swimSpeedMultiplier
}

// SetSwimSpeedMultiplier sets the transient water-speed multiplier.
func (mc *AuthoritativeMovementComponent) SetSwimSpeedMultiplier(multiplier float32) {
mc.swimSpeedMultiplier = multiplier
}

// XCollision returns true if the movement component is collided with a block
// on the x-axis.
func (mc *AuthoritativeMovementComponent) XCollision() bool {
Expand Down Expand Up @@ -791,28 +875,35 @@ func (mc *AuthoritativeMovementComponent) Update(pk *packet.PlayerAuthInput) {
mc.sneaking = pk.InputData.Load(packet.InputFlagSneakDown)
}

wasSwimming := mc.swimming
if pk.InputData.Load(packet.InputFlagStopSwimming) {
mc.swimming = false
} else if pk.InputData.Load(packet.InputFlagStartSwimming) {
mc.swimming = true
mc.sneaking = false
}
if wasSwimming {
mc.swimAmount = game.ClampFloat(mc.swimAmount+0.1, 0, 1)
} else {
mc.swimAmount = game.ClampFloat(mc.swimAmount-0.1, 0, 1)
}
mc.autoJumpingInWater = pk.InputData.Load(packet.InputFlagAutoJumpingInWater)
mc.wantDown = pk.InputData.Load(packet.InputFlagWantDown)
mc.wantDownSlow = pk.InputData.Load(packet.InputFlagWantDownSlow)

mc.mPlayer.Dbg.Notify(
player.DebugModeMovementSim,
true,
"rawMoveVector=%v",
pk.MoveVector,
)

maxImpulse := float32(1.0)
/* if pk.MoveVector[0] != 0 && pk.MoveVector[1] != 0 {
maxImpulse = game.MaxNormalizedImpulse
} */
if mc.mPlayer.StartUseConsumableTick != 0 {
maxImpulse *= game.MaxConsumingImpulse
}
if mc.sneaking {
maxImpulse *= game.MaxSneakImpulse
}
pk.MoveVector[0] = game.ClampFloat(pk.MoveVector[0], -maxImpulse, maxImpulse)
pk.MoveVector[1] = game.ClampFloat(pk.MoveVector[1], -maxImpulse, maxImpulse)
pk.MoveVector[0] = game.ClampFloat(pk.MoveVector[0], -1, 1)
pk.MoveVector[1] = game.ClampFloat(pk.MoveVector[1], -1, 1)

mc.jumping = pk.InputData.Load(packet.InputFlagStartJumping)
mc.pressingJump = pk.InputData.Load(packet.InputFlagJumping)
mc.effectiveJumping = mc.pressingJump || mc.autoJumpingInWater || pk.InputData.Load(packet.InputFlagAscendBlock)
mc.jumpHeight = game.DefaultJumpHeight
if jumpBoost, ok := mc.mPlayer.Effects().Get(packet.EffectJumpBoost); ok {
mc.jumpHeight += float32(jumpBoost.Amplifier) * 0.1
Expand All @@ -838,6 +929,21 @@ func (mc *AuthoritativeMovementComponent) Update(pk *packet.PlayerAuthInput) {
}

mc.impulse = pk.MoveVector.Mul(0.98)
mc.mPlayer.Dbg.Notify(
player.DebugModeMovementSim,
true,
"input swimming=%t swimAmount=%.1f sneaking=%t jumping=%t pressingJump=%t effectiveJumping=%t autoJumpingInWater=%t wantDown=%t wantDownSlow=%t jumpCurrentRaw=%t",
mc.swimming,
mc.swimAmount,
mc.sneaking,
mc.jumping,
mc.pressingJump,
mc.effectiveJumping,
mc.autoJumpingInWater,
mc.wantDown,
mc.wantDownSlow,
pk.InputData.Load(packet.InputFlagJumpCurrentRaw),
)
simulation.SimulatePlayerMovement(mc.mPlayer, mc)

// On older versions, there seems to be a delay before the sprinting status is actually applied.
Expand Down Expand Up @@ -876,6 +982,13 @@ func (mc *AuthoritativeMovementComponent) Update(pk *packet.PlayerAuthInput) {
}

mc.glideBoostTicks--
if mc.dolphinBoostTicks > 0 {
mc.dolphinBoostTicks--
if mc.dolphinBoostTicks <= 0 {
mc.dolphinBoostTicks = 0
mc.swimSpeedMultiplier = 1
}
}
mc.ticksSinceKb++
mc.ticksSinceTeleport++
if mc.jumpDelay > 0 {
Expand All @@ -897,6 +1010,14 @@ func (mc *AuthoritativeMovementComponent) ServerUpdate(pk packet.Packet) {
pk.Operation,
))
}
case *packet.MovementEffect:
if pk.EntityRuntimeID == mc.mPlayer.RuntimeId && pk.Type == packet.MovementEffectTypeDolphinBoost {
mc.dolphinBoostTicks = max(0, int64(pk.Duration))
mc.swimSpeedMultiplier = 1
if mc.dolphinBoostTicks > 0 {
mc.swimSpeedMultiplier = 2
}
}
case *packet.MoveActorAbsolute:
if utils.HasFlag(uint64(pk.Flags), packet.MoveFlagTeleport) {
mc.SetPendingTeleportPos(pk.Position)
Expand Down Expand Up @@ -1027,6 +1148,11 @@ func (mc *AuthoritativeMovementComponent) Sync() {
} else {
flags = utils.RemoveFlag(flags, entity.DataFlagImmobile)
}
if mc.swimming {
flags = utils.AddFlag(flags, entity.DataFlagSwimming)
} else {
flags = utils.RemoveFlag(flags, entity.DataFlagSwimming)
}
actorData.EntityMetadata[entity.DataKeyFlags] = flags
}
mc.mPlayer.SendPacketToClient(actorData)
Expand Down Expand Up @@ -1072,6 +1198,10 @@ func (mc *AuthoritativeMovementComponent) ResetTransferState(pos mgl32.Vec3) {

mc.movementSpeed = mc.defaultMovementSpeed
mc.airSpeed = 0.02
mc.underwaterMovementSpeed = 0.02
mc.lavaMovementSpeed = 0.02
mc.swimSpeedMultiplier = 1
mc.dolphinBoostTicks = 0
mc.serverUpdatedSpeed = false

mc.knockback = mgl32.Vec3{}
Expand All @@ -1091,9 +1221,15 @@ func (mc *AuthoritativeMovementComponent) ResetTransferState(pos mgl32.Vec3) {

mc.sneaking = false
mc.pressingSneak = false
mc.swimming = false
mc.swimAmount = 0
mc.autoJumpingInWater = false
mc.wantDown = false
mc.wantDownSlow = false

mc.jumping = false
mc.pressingJump = false
mc.effectiveJumping = false
mc.jumpDelay = 0

mc.collideX = false
Expand Down
Loading
Loading