From 607e86f801bb6316424b87ac8a676e2b84ac842e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20S=C3=BCtterlin?= <68386188+psu-de@users.noreply.github.com> Date: Wed, 27 Mar 2024 19:26:51 +0100 Subject: [PATCH] added MutableVector3, MutableAABB and removed some unnecessary allocations --- .../Components/FluidPhysicsComponent.cs | 26 +- Components/MineSharp.Physics/PlayerPhysics.cs | 151 ++++--- .../MineSharp.Physics/Utils/PoseUtils.cs | 2 +- .../MineSharp.Physics/Utils/WorldUtils.cs | 2 +- .../Iterators/BoundingBoxIterator.cs | 12 +- .../BlockCollisionShapeData.cs | 11 +- MineSharp.Bot/Plugins/EntityPlugin.cs | 46 ++- MineSharp.Bot/Plugins/PhysicsPlugin.cs | 2 +- MineSharp.Bot/Plugins/PlayerPlugin.cs | 8 +- MineSharp.Core/Common/Entities/Entity.cs | 11 +- MineSharp.Core/Geometry/AABB.cs | 211 +++++----- MineSharp.Core/Geometry/Vector3.cs | 387 +++++++++--------- 12 files changed, 430 insertions(+), 439 deletions(-) diff --git a/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs b/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs index b37fd8ea..970ebe4c 100644 --- a/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs +++ b/Components/MineSharp.Physics/Components/FluidPhysicsComponent.cs @@ -47,15 +47,15 @@ private bool DoFluidPushing(BlockType type, double factor, out double height) .GetBoundingBox() .Deflate(0.001d, 0.001d, 0.001d); - var fromX = (int)Math.Floor(aabb.MinX); - var toX = (int)Math.Ceiling(aabb.MaxX); - var fromY = (int)Math.Floor(aabb.MinY); - var toY = (int)Math.Ceiling(aabb.MaxY); - var fromZ = (int)Math.Floor(aabb.MinZ); - var toZ = (int)Math.Ceiling(aabb.MaxZ); + var fromX = (int)Math.Floor(aabb.Min.X); + var toX = (int)Math.Ceiling(aabb.Max.X); + var fromY = (int)Math.Floor(aabb.Min.Y); + var toY = (int)Math.Ceiling(aabb.Max.Y); + var fromZ = (int)Math.Floor(aabb.Min.Z); + var toZ = (int)Math.Ceiling(aabb.Max.Z); var d0 = 0.0d; var result = false; - var vel = Vector3.Zero; + var vel = Vector3.Zero.Clone(); var k1 = 0; var pos = new MutablePosition(0, 0, 0); @@ -72,11 +72,11 @@ private bool DoFluidPushing(BlockType type, double factor, out double height) continue; var fHeight = y + this.GetFluidHeight(this.World, block); - if (fHeight < aabb.MinY) + if (fHeight < aabb.Min.Y) continue; result = true; - d0 = Math.Max(fHeight - aabb.MinY, d0); + d0 = Math.Max(fHeight - aabb.Min.Y, d0); var flow = this.GetFlow(this.World, block); if (d0 < 0.4d) @@ -107,7 +107,7 @@ private bool DoFluidPushing(BlockType type, double factor, out double height) vel.Scale(PhysicsConst.VELOCITY_SCALE); } - this.Player.Entity!.Velocity.Add(vel); + (this.Player.Entity!.Velocity as MutableVector3)!.Add(vel); return result; } @@ -123,7 +123,7 @@ private float GetFluidHeight(IWorld world, Block block) return (8 - block.GetProperty("level")) / MAX_FLUID_HEIGHT; } - private Vector3 GetFlow(IWorld world, Block fluid) + private MutableVector3 GetFlow(IWorld world, Block fluid) { var dX = 0.0d; var dZ = 0.0d; @@ -165,13 +165,13 @@ private Vector3 GetFlow(IWorld world, Block fluid) dZ += direction.Z * heightDiff; } - var vel = new Vector3(dX, 0, dZ); + var vel = new MutableVector3(dX, 0, dZ); // TODO: FluidUtils.GetFlow() difference with java: // Block property falling // FlowingFluid.java:85 - return vel.Normalized(); + return vel.Normalize(); } private bool AffectsFlow(Block first, Block second) diff --git a/Components/MineSharp.Physics/PlayerPhysics.cs b/Components/MineSharp.Physics/PlayerPhysics.cs index 05f42b45..44bc3f9c 100644 --- a/Components/MineSharp.Physics/PlayerPhysics.cs +++ b/Components/MineSharp.Physics/PlayerPhysics.cs @@ -54,6 +54,8 @@ public class PlayerPhysics /// public readonly PlayerState State = new PlayerState(); + private readonly MutableVector3 playerPosition; + private readonly MutableVector3 playerVelocity; private readonly FluidPhysicsComponent fluidPhysics; private readonly MovementInput movementInput; private readonly Attribute speedAttribute; @@ -91,6 +93,12 @@ public PlayerPhysics(MinecraftData data, MinecraftPlayer player, IWorld world, I UUID.Parse(PhysicsConst.SPRINTING_UUID), PhysicsConst.PLAYER_SPRINT_SPEED, ModifierOp.Multiply); + + this.playerVelocity = this.Player.Entity.Velocity as MutableVector3 ?? + throw new ArgumentException("entity is not initialized or velocity is not mutable."); + + this.playerPosition = this.Player.Entity.Position as MutableVector3 ?? + throw new ArgumentException("entity position is not mutable"); } /// @@ -168,7 +176,7 @@ private void MovementTick() // && !this.Player.IsFlying if (this.State.WasTouchingWater && this.movementInput.Controls.SneakingKeyDown) { - this.Player.Entity!.Velocity.Add(PhysicsConst.WaterDrag); + this.playerVelocity.Add(PhysicsConst.WaterDrag); } // water vision @@ -180,7 +188,7 @@ private void MovementTick() if (this.State.NoJumpDelay > 0) this.State.NoJumpDelay--; - this.TruncateVelocity(this.Player.Entity!.Velocity); + this.TruncateVelocity(this.playerVelocity); // && !this.Player.IsFlying if (this.movementInput.Controls.JumpingKeyDown) @@ -225,7 +233,6 @@ private void Travel() private void TravelNormally(double gravity, double dx, double dz) { - var moveVector = new Vector3(dx, 0, dz); var blockBelow = this.World.GetBlockAt(new Position( this.Player.Entity!.Position.X, this.Player.Entity!.Position.Y - 0.5f, @@ -239,11 +246,11 @@ private void TravelNormally(double gravity, double dx, double dz) ? PhysicsConst.SPRINTING_FLYING_SPEED : PhysicsConst.FLYING_SPEED; - this.MoveRelative(moveVector, (float)frictionInfluencedSpeed, this.Player.Entity.Yaw); + this.MoveRelative(dx, 0, dz, (float)frictionInfluencedSpeed, this.Player.Entity.Yaw); this.CheckClimbable(); this.Move(); - var vel = this.Player.Entity.Velocity.Clone(); + var vel = (Vector3)this.Player.Entity.Velocity.Clone(); var blockAtFeet = this.World.GetBlockAt((Position)this.Player.Entity.Position); if ((this.State.HorizontalCollision || this.movementInput.Controls.JumpingKeyDown) @@ -264,9 +271,7 @@ private void TravelNormally(double gravity, double dx, double dz) else velY -= gravity; - this.Player.Entity.Velocity.X = vel.X * speedFactor; - this.Player.Entity.Velocity.Y = velY * 0.98f; - this.Player.Entity.Velocity.Z = vel.Z * speedFactor; + this.playerVelocity.Set(vel.X * speedFactor, velY * 0.98f, vel.Z * speedFactor); } private void CheckClimbable() @@ -283,9 +288,7 @@ private void CheckClimbable() if (y < 0.0 && blockAtFeet.Info.Type != BlockType.Scaffolding && this.movementInput.Controls.SneakingKeyDown) y = 0.0; - this.Player.Entity!.Velocity.X = x; - this.Player.Entity!.Velocity.Y = y; - this.Player.Entity!.Velocity.Z = z; + this.playerVelocity.Set(x, y, z); } private void TravelWater(bool isFalling, double dx, double dz) @@ -307,9 +310,8 @@ private void TravelWater(bool isFalling, double dx, double dz) if (this.Player.Entity!.GetEffectLevel(EffectType.DolphinsGrace).HasValue) waterFactor = 0.96f; - - var moveVector = new Vector3(dx, 0, dz); - this.MoveRelative(moveVector, speedFactor, this.Player.Entity!.Yaw); + + this.MoveRelative(dx, 0, dz, speedFactor, this.Player.Entity!.Yaw); this.Move(); // TODO: Finish water movement @@ -323,19 +325,18 @@ private void Move() { vec.Multiply(this.State.StuckSpeedMultiplier); this.State.StuckSpeedMultiplier = Vector3.Zero; - this.Player.Entity!.Velocity.X = 0; - this.Player.Entity!.Velocity.Y = 0; - this.Player.Entity!.Velocity.Z = 0; + + this.playerVelocity.Set(0, 0, 0); } - this.MaybeBackOffFromEdge(ref vec); + this.MaybeBackOffFromEdge(vec); var vec3 = this.Collide(vec); var length = vec3.LengthSquared(); if (length > 1.0E-7D) { // reset fall distance - this.Player.Entity!.Position.Add(vec3); + this.playerPosition.Add(vec3); } var collidedX = Math.Abs(vec.X - vec3.X) > 1.0E-5F; @@ -349,22 +350,26 @@ private void Move() if (this.State.HorizontalCollision) { if (collidedX) - this.Player.Entity.Velocity.X = 0.0; + { + this.playerVelocity.SetX(0.0); + } else - this.Player.Entity.Velocity.Z = 0.0; + { + this.playerVelocity.SetZ(0.0); + } } else this.State.MinorHorizontalCollision = false; if (this.State.VerticalCollision) { - this.Player.Entity.Velocity.Y = 0.0; + this.playerVelocity.SetY(0.0); } } private Vector3 Collide(Vector3 vec) { var aabb = this.Player.Entity!.GetBoundingBox(); - var collidedVec = vec.LengthSquared() == 0.0 ? vec : CheckBoundingBoxCollisions(vec, aabb); + var collidedVec = vec.LengthSquared() == 0.0 ? vec : CheckBoundingBoxCollisions(vec.X, vec.Y, vec.Z, aabb); var collidedX = Math.Abs(vec.X - collidedVec.X) > 1.0E-5; var collidedY = Math.Abs(vec.Y - collidedVec.Y) > 1.0E-5; @@ -374,16 +379,16 @@ private Vector3 Collide(Vector3 vec) if (hitGround && (collidedX || collidedZ)) { var collidedUpXZ = CheckBoundingBoxCollisions( - new Vector3(vec.X, PhysicsConst.MAX_UP_STEP, vec.Z), - aabb); + vec.X, PhysicsConst.MAX_UP_STEP, vec.Z, aabb); + var collidedUp0 = CheckBoundingBoxCollisions( - new Vector3(0.0, PhysicsConst.MAX_UP_STEP, 0.0), + 0, PhysicsConst.MAX_UP_STEP, 0, aabb.Clone().Expand(vec.X, 0, vec.Z)); if (collidedUp0.Y < PhysicsConst.MAX_UP_STEP) { var collidedAbove = CheckBoundingBoxCollisions( - new Vector3(vec.X, 0, vec.Z), + vec.X, 0.0, vec.Z, aabb.Clone().Offset(collidedUp0.X, collidedUp0.Y, collidedUp0.Z)) .Plus(collidedUp0); @@ -397,7 +402,7 @@ private Vector3 Collide(Vector3 vec) { collidedUpXZ.Add( CheckBoundingBoxCollisions( - new Vector3(0.0, -collidedUpXZ.Y + vec.Y, 0.0), + 0.0, -collidedUpXZ.Y + vec.Y, 0.0, aabb.Clone().Offset(collidedUpXZ.X, collidedUpXZ.Y, collidedUpXZ.Z))); return collidedUpXZ; @@ -427,46 +432,46 @@ private bool IsCollisionMinor(Vector3 vec) return d7 < 0.13962634F; } - private Vector3 CheckBoundingBoxCollisions(Vector3 direction, AABB aabb) + private MutableVector3 CheckBoundingBoxCollisions(double dx, double dy, double dz, AABB aabb) { // TODO: Entity collision boxes // TODO: World border collision - aabb = aabb.Clone(); + var mutableAabb = aabb.Clone(); var shapes = WorldUtils.GetWorldBoundingBoxes( - aabb.Clone().Expand(direction.X, direction.Y, direction.Z), + aabb.Clone().Expand(dx, dy, dz), this.World, this.Data); if (shapes.Length == 0) - return direction; + return new MutableVector3(dx, dy, dz); // check for collisions - var mX = direction.X; - var mY = direction.Y; - var mZ = direction.Z; + var mX = dx; + var mY = dy; + var mZ = dz; if (mY != 0.0) { - mY = CalculateAxisOffset(Axis.Y, aabb, shapes, mY); + mY = CalculateAxisOffset(Axis.Y, mutableAabb, shapes, mY); if (mY != 0.0) - aabb.Offset(0, mY, 0); + mutableAabb.Offset(0, mY, 0); } var zDominant = Math.Abs(mX) < Math.Abs(mZ); if (zDominant && mZ != 0.0) { - mZ = CalculateAxisOffset(Axis.Z, aabb, shapes, mZ); + mZ = CalculateAxisOffset(Axis.Z, mutableAabb, shapes, mZ); if (mZ != 0.0) - aabb.Offset(0, 0, mZ); + mutableAabb.Offset(0, 0, mZ); } if (mX != 0.0) { - mX = CalculateAxisOffset(Axis.X, aabb, shapes, mX); + mX = CalculateAxisOffset(Axis.X, mutableAabb, shapes, mX); if (mX != 0.0) - aabb.Offset(mX, 0, 0); + mutableAabb.Offset(mX, 0, 0); } if (!zDominant && mZ != 0.0) @@ -474,7 +479,7 @@ private Vector3 CheckBoundingBoxCollisions(Vector3 direction, AABB aabb) mZ = CalculateAxisOffset(Axis.Z, aabb, shapes, mZ); } - return new Vector3(mX, mY, mZ); + return new MutableVector3(mX, mY, mZ); } private double CalculateAxisOffset(Axis axis, AABB aabb, AABB[] shapes, double displacement) @@ -489,7 +494,7 @@ private double CalculateAxisOffset(Axis axis, AABB aabb, AABB[] shapes, double d return value; } - private void MaybeBackOffFromEdge(ref Vector3 vec) + private void MaybeBackOffFromEdge(MutableVector3 vec) { // TODO Fix differences with java // Player.java:1054 @@ -540,26 +545,35 @@ private void MaybeBackOffFromEdge(ref Vector3 vec) }; } - vec.X = x; - vec.Z = z; + vec.SetX(x); + vec.SetZ(z); } - private void MoveRelative(Vector3 vec, float scale, float yaw) + private void MoveRelative(double dx, double dy, double dz, float scale, float yaw) { - var length = vec.LengthSquared(); + var length = dx * dx + dy * dy + dz * dz; if (length < 1.0E-7D) return; if (length > 1.0) - vec = vec.Normalized(); + { + // normalize + dx = 1 / length * dx; + dy = 1 / length * dy; + dz = 1 / length * dz; + } - vec.Scale(scale); + dx *= scale; + dy *= scale; + dz *= scale; var sin = MathF.Sin(yaw * (MathF.PI / 180.0F)); var cos = MathF.Cos(yaw * (MathF.PI / 180.0F)); - this.Player.Entity!.Velocity.X += vec.X * cos - vec.Z * sin; - this.Player.Entity!.Velocity.Y += vec.Y; - this.Player.Entity!.Velocity.Z += vec.Z * cos + vec.X * sin; + + this.playerVelocity.Add( + dx * cos - dz * sin, + dy, + dz * cos + dx * sin); } private void TryJumping() @@ -595,19 +609,20 @@ private void JumpFromGround() { var jumpBoostFactor = 0.1d * (this.Player.Entity!.GetEffectLevel(EffectType.JumpBoost) + 1) ?? 0; - this.Player.Entity!.Velocity.Y = - 0.42d * WorldUtils.GetBlockJumpFactor((Position)this.Player.Entity!.Position, this.World) + jumpBoostFactor; + this.playerVelocity.SetY( + 0.42 * WorldUtils.GetBlockJumpFactor((Position)this.Player.Entity.Position, this.World) + jumpBoostFactor); + if (!this.State.IsSprinting) return; var yaw = this.Player.Entity!.Yaw * (MathF.PI / 180.0f); - this.Player.Entity!.Velocity.X -= 0.2F * MathF.Sin(yaw); - this.Player.Entity!.Velocity.Z += 0.2F * MathF.Cos(yaw); + + this.playerVelocity.Add(-0.2 * Math.Sin(yaw), 0, 0.2 * Math.Cos(yaw)); } private void JumpInFluid() { - this.Player.Entity!.Velocity.Y += PhysicsConst.FLUID_JUMP_FACTOR; + this.playerVelocity.Add(0.0, PhysicsConst.FLUID_JUMP_FACTOR, 0.0); } private void UpdateSprinting() @@ -685,30 +700,32 @@ private void PushTowardsClosestSpace(double x, double z) return; if (direction.X != 0.0) - this.Player.Entity!.Velocity.X = 0.1d * direction.X; + { + this.playerVelocity.SetX(0.1d * direction.X); + } else - this.Player.Entity!.Velocity.Z = 0.1 * direction.Z; + { + this.playerVelocity.SetZ(0.1 * direction.Z); + } } private bool CollidesWithSuffocatingBlock(Position position) { var bb = this.Player.Entity!.GetBoundingBox(); - bb.Min.X = position.X; - bb.Min.Z = position.Z; - bb.Max.X = position.X + 1.0f; - bb.Max.Z = position.Z + 1.0f; + bb.Min.Set(position.X, 0, position.Z); + bb.Max.Set(position.X + 1.0, 0, position.Z + 1.0); bb.Deflate(1.0E-7D, 1.0E-7D, 1.0E-7D); return WorldUtils.CollidesWithWorld(bb, this.World, this.Data); } - private void TruncateVelocity(Vector3 vec) + private void TruncateVelocity(MutableVector3 vec) { if (Math.Abs(vec.X) < PhysicsConst.VELOCITY_THRESHOLD) - vec.X = 0; + vec.SetX(0); if (Math.Abs(vec.Y) < PhysicsConst.VELOCITY_THRESHOLD) - vec.Y = 0; + vec.SetY(0); if (Math.Abs(vec.Z) < PhysicsConst.VELOCITY_THRESHOLD) - vec.Z = 0; + vec.SetZ(0); } } diff --git a/Components/MineSharp.Physics/Utils/PoseUtils.cs b/Components/MineSharp.Physics/Utils/PoseUtils.cs index d54c6d0e..6ef915a0 100644 --- a/Components/MineSharp.Physics/Utils/PoseUtils.cs +++ b/Components/MineSharp.Physics/Utils/PoseUtils.cs @@ -19,7 +19,7 @@ internal static class PoseUtils { EntityPose.Dying, CreateAABB(0.2f, 0.2f) }, }; - public static AABB GetBBForPose(EntityPose pose) + public static MutableAABB GetBBForPose(EntityPose pose) => PoseDimensions[pose].Clone(); public static bool WouldPlayerCollideWithPose(MinecraftPlayer player, EntityPose pose, IWorld world, MinecraftData data) diff --git a/Components/MineSharp.Physics/Utils/WorldUtils.cs b/Components/MineSharp.Physics/Utils/WorldUtils.cs index ca974444..ebfe3e57 100644 --- a/Components/MineSharp.Physics/Utils/WorldUtils.cs +++ b/Components/MineSharp.Physics/Utils/WorldUtils.cs @@ -22,7 +22,7 @@ public static AABB[] GetWorldBoundingBoxes(AABB bb, IWorld world, MinecraftData foreach (var block in blocks) { var shapes = data.BlockCollisionShapes.GetForBlock(block); - bbs.AddRange(shapes.Select(x => x.Offset(block.Position.X, block.Position.Y, block.Position.Z))); + bbs.AddRange(shapes.Select(x => x.Clone().Offset(block.Position.X, block.Position.Y, block.Position.Z))); } return bbs.ToArray(); diff --git a/Components/MineSharp.World/Iterators/BoundingBoxIterator.cs b/Components/MineSharp.World/Iterators/BoundingBoxIterator.cs index 958627a0..79240a3b 100644 --- a/Components/MineSharp.World/Iterators/BoundingBoxIterator.cs +++ b/Components/MineSharp.World/Iterators/BoundingBoxIterator.cs @@ -17,12 +17,12 @@ public class BoundingBoxIterator : IWorldIterator /// public BoundingBoxIterator(AABB aabb) { - var minX = (int)Math.Floor(aabb.MinX - 1.0E-7D) - 1; - var maxX = (int)Math.Floor(aabb.MaxX + 1.0E-7D) + 1; - var minY = (int)Math.Floor(aabb.MinY - 1.0E-7D) - 1; - var maxY = (int)Math.Floor(aabb.MaxY + 1.0E-7D) + 1; - var minZ = (int)Math.Floor(aabb.MinZ - 1.0E-7D) - 1; - var maxZ = (int)Math.Floor(aabb.MaxZ + 1.0E-7D) + 1; + var minX = (int)Math.Floor(aabb.Min.X - 1.0E-7D) - 1; + var maxX = (int)Math.Floor(aabb.Max.X + 1.0E-7D) + 1; + var minY = (int)Math.Floor(aabb.Min.Y - 1.0E-7D) - 1; + var maxY = (int)Math.Floor(aabb.Max.Y + 1.0E-7D) + 1; + var minZ = (int)Math.Floor(aabb.Min.Z - 1.0E-7D) - 1; + var maxZ = (int)Math.Floor(aabb.Max.Z + 1.0E-7D) + 1; this._iterator = new XYZIterator( new Position(minX, minY, minZ), diff --git a/Data/MineSharp.Data/BlockCollisionShapes/BlockCollisionShapeData.cs b/Data/MineSharp.Data/BlockCollisionShapes/BlockCollisionShapeData.cs index bb8fb322..d636e808 100644 --- a/Data/MineSharp.Data/BlockCollisionShapes/BlockCollisionShapeData.cs +++ b/Data/MineSharp.Data/BlockCollisionShapes/BlockCollisionShapeData.cs @@ -11,12 +11,15 @@ internal class BlockCollisionShapeData(IDataProvider(provider), IBlockCollisionShapeData { private Dictionary typeToIndices = new(); - private Dictionary indexToShape = new(); + private Dictionary indexToShape = new(); protected override void InitializeData(BlockCollisionShapeDataBlob data) { this.typeToIndices = data.BlockToIndicesMap; - this.indexToShape = data.IndexToShapeMap; + this.indexToShape = data.IndexToShapeMap + .ToDictionary( + x => x.Key, + x => x.Value.Select(y => new AABB(y[0], y[1], y[2], y[3], y[4], y[5])).ToArray()); } public int[] GetShapeIndices(BlockType type) @@ -28,7 +31,5 @@ public int[] GetShapeIndices(BlockType type) } public AABB[] GetShapes(int shapeIndex) - => indexToShape[shapeIndex] // TODO: Use pooled AABB's - .Select(x => new AABB(x[0], x[1], x[2], x[3], x[4], x[5])) - .ToArray(); + => indexToShape[shapeIndex]; } diff --git a/MineSharp.Bot/Plugins/EntityPlugin.cs b/MineSharp.Bot/Plugins/EntityPlugin.cs index 4508a468..12bf6ab2 100644 --- a/MineSharp.Bot/Plugins/EntityPlugin.cs +++ b/MineSharp.Bot/Plugins/EntityPlugin.cs @@ -81,10 +81,10 @@ private Task HandleSpawnLivingEntityPacket(SpawnLivingEntityPacket packet) var entityInfo = this.Bot.Data.Entities.ById(packet.EntityType)!; var newEntity = new Entity( - entityInfo, packet.EntityId, new Vector3(packet.X, packet.Y, packet.Z), + entityInfo, packet.EntityId, new MutableVector3(packet.X, packet.Y, packet.Z), packet.Pitch, packet.Yaw, - new Vector3( + new MutableVector3( NetUtils.ConvertToVelocity(packet.VelocityX), NetUtils.ConvertToVelocity(packet.VelocityY), NetUtils.ConvertToVelocity(packet.VelocityZ)), @@ -103,10 +103,10 @@ private Task HandleSpawnEntityPacket(SpawnEntityPacket packet) var entityInfo = this.Bot.Data.Entities.ById(packet.EntityType)!; var newEntity = new Entity( - entityInfo, packet.EntityId, new Vector3(packet.X, packet.Y, packet.Z), + entityInfo, packet.EntityId, new MutableVector3(packet.X, packet.Y, packet.Z), packet.Pitch, packet.Yaw, - new Vector3( + new MutableVector3( NetUtils.ConvertToVelocity(packet.VelocityX), NetUtils.ConvertToVelocity(packet.VelocityY), NetUtils.ConvertToVelocity(packet.VelocityZ)), @@ -143,10 +143,12 @@ private Task HandleSetEntityVelocityPacket(SetEntityVelocityPacket packet) return Task.CompletedTask; } - entity.Velocity.X = NetUtils.ConvertToVelocity(packet.VelocityX); - entity.Velocity.Y = NetUtils.ConvertToVelocity(packet.VelocityY); - entity.Velocity.Z = NetUtils.ConvertToVelocity(packet.VelocityZ); - + (entity.Position as MutableVector3)!.Set( + NetUtils.ConvertToVelocity(packet.VelocityX), + NetUtils.ConvertToVelocity(packet.VelocityY), + NetUtils.ConvertToVelocity(packet.VelocityZ) + ); + return Task.CompletedTask; } @@ -158,10 +160,11 @@ private Task HandleUpdateEntityPositionPacket(EntityPositionPacket packet) if (!this.Entities.TryGetValue(packet.EntityId, out var entity)) return Task.CompletedTask; - entity.Position.Add(new Vector3( + (entity.Position as MutableVector3)!.Add( NetUtils.ConvertDeltaPosition(packet.DeltaX), NetUtils.ConvertDeltaPosition(packet.DeltaY), - NetUtils.ConvertDeltaPosition(packet.DeltaZ))); + NetUtils.ConvertDeltaPosition(packet.DeltaZ) + ); entity.IsOnGround = packet.OnGround; @@ -177,10 +180,10 @@ private Task HandleUpdateEntityPositionAndRotationPacket(EntityPositionAndRotati if (!this.Entities.TryGetValue(packet.EntityId, out var entity)) return Task.CompletedTask; - entity.Position.Add(new Vector3( + (entity.Position as MutableVector3)!.Add( NetUtils.ConvertDeltaPosition(packet.DeltaX), NetUtils.ConvertDeltaPosition(packet.DeltaY), - NetUtils.ConvertDeltaPosition(packet.DeltaZ))); + NetUtils.ConvertDeltaPosition(packet.DeltaZ)); entity.Yaw = NetUtils.FromAngleByte(packet.Yaw); entity.Pitch = NetUtils.FromAngleByte(packet.Pitch); @@ -215,9 +218,8 @@ private Task HandleTeleportEntityPacket(TeleportEntityPacket packet) if (!this.Entities.TryGetValue(packet.EntityId, out var entity)) return Task.CompletedTask; - entity.Position.X = packet.X; - entity.Position.Y = packet.Y; - entity.Position.Z = packet.Z; + (entity.Position as MutableVector3)! + .Set(packet.X, packet.Y, packet.Z); entity.Yaw = NetUtils.FromAngleByte(packet.Yaw); entity.Pitch = NetUtils.FromAngleByte(packet.Pitch); @@ -252,20 +254,22 @@ private async Task HandleSynchronizePlayerPosition(PlayerPositionPacket packet) await this.WaitForInitialization(); + var position = (this._playerPlugin!.Entity!.Position as MutableVector3)!; + if ((packet.Flags & 0x01) == 0x01) - this._playerPlugin!.Entity!.Position.X += packet.X; + position.Add(packet.X, 0, 0); else - this._playerPlugin!.Entity!.Position.X = packet.X; + position.SetX(packet.X); if ((packet.Flags & 0x02) == 0x02) - this._playerPlugin!.Entity!.Position.Y += packet.Y; + position.Add(0, packet.Y, 0); else - this._playerPlugin!.Entity!.Position.Y = packet.Y; + position.SetY(packet.Y); if ((packet.Flags & 0x04) == 0x04) - this._playerPlugin!.Entity!.Position.Z += packet.Z; + position.Add(0, 0, packet.Z); else - this._playerPlugin!.Entity!.Position.Z = packet.Z; + position.SetZ(packet.Z); if ((packet.Flags & 0x08) == 0x08) this._playerPlugin!.Entity!.Pitch += packet.Pitch; diff --git a/MineSharp.Bot/Plugins/PhysicsPlugin.cs b/MineSharp.Bot/Plugins/PhysicsPlugin.cs index 3f835178..71daafd7 100644 --- a/MineSharp.Bot/Plugins/PhysicsPlugin.cs +++ b/MineSharp.Bot/Plugins/PhysicsPlugin.cs @@ -209,7 +209,7 @@ public Task LookAt(Block block, float smoothness = ROTATION_SMOOTHNESS) foreach (var bb in bbs) { - bb.Offset(block.Position.X, block.Position.Y, block.Position.Z); + bb.Clone().Offset(block.Position.X, block.Position.Y, block.Position.Z); if (bb.IntersectsLine(position, lookVector)) return block; diff --git a/MineSharp.Bot/Plugins/PlayerPlugin.cs b/MineSharp.Bot/Plugins/PlayerPlugin.cs index 6c977856..dd121824 100644 --- a/MineSharp.Bot/Plugins/PlayerPlugin.cs +++ b/MineSharp.Bot/Plugins/PlayerPlugin.cs @@ -158,10 +158,10 @@ protected override async Task Init() var entity = new Entity( this.Bot.Data.Entities.ByType(EntityType.Player)!, loginPacket.EntityId, - new Vector3(positionPacket.X, positionPacket.Y, positionPacket.Z), + new MutableVector3(positionPacket.X, positionPacket.Y, positionPacket.Z), positionPacket.Pitch, positionPacket.Yaw, - new Vector3(0, 0, 0), + new MutableVector3(0, 0, 0), false, new Dictionary()); @@ -290,13 +290,13 @@ private Task HandleSpawnPlayer(SpawnPlayerPacket packet) var entity = new Entity( this.Bot.Data.Entities.ByType(EntityType.Player)!, packet.EntityId, - new Vector3( + new MutableVector3( packet.X, packet.Y, packet.Z), NetUtils.FromAngleByte((sbyte)packet.Pitch), NetUtils.FromAngleByte((sbyte)packet.Yaw), - Vector3.Zero, + new MutableVector3(0, 0, 0), true, new Dictionary()); player.Entity = entity; diff --git a/MineSharp.Core/Common/Entities/Entity.cs b/MineSharp.Core/Common/Entities/Entity.cs index c2471959..31480ae4 100644 --- a/MineSharp.Core/Common/Entities/Entity.cs +++ b/MineSharp.Core/Common/Entities/Entity.cs @@ -117,12 +117,12 @@ public void AddAttribute(Attribute attribute) /// Return the bounding box for this entity. /// /// - public AABB GetBoundingBox() + public MutableAABB GetBoundingBox() { var half = this.Info.Width / 2.0f; var height = this.Info.Height; - return new AABB( + return new MutableAABB( this.Position.X - half, this.Position.Y, this.Position.Z - half, @@ -139,16 +139,13 @@ public Vector3 GetLookVector() { var pitchRadians = this.Pitch * (MathF.PI / 180.0f); var yawRadians = this.Yaw * (MathF.PI / 180.0); - + var len = Math.Cos(pitchRadians); var x = len * Math.Sin(-yawRadians); var y = -Math.Sin(pitchRadians); var z = len * Math.Cos(yawRadians); - var vec = new Vector3(x, y, z); - vec.Normalize(); - - return vec; + return new MutableVector3(x, y, z).Normalize(); } /// diff --git a/MineSharp.Core/Geometry/AABB.cs b/MineSharp.Core/Geometry/AABB.cs index 5a6cfefe..ec311e37 100644 --- a/MineSharp.Core/Geometry/AABB.cs +++ b/MineSharp.Core/Geometry/AABB.cs @@ -8,70 +8,50 @@ namespace MineSharp.Core.Geometry; /// public class AABB { - /// - /// Lower X coordinate - /// - public double MinX => this.Min.X; - - /// - /// Lower Y coordinate - /// - public double MinY => this.Min.Y; - - /// - /// Lower Z coordinate - /// - public double MinZ => this.Min.Z; - - /// - /// Upper X coordinate - /// - public double MaxX => this.Max.X; - - /// - /// Upper Y coordinate - /// - public double MaxY => this.Max.Y; - - /// - /// Upper Z coordinate - /// - public double MaxZ => this.Max.Z; /// /// Width of this bounding box (MaxX - MinX) /// - public double Width => this.MaxX - this.MinX; + public double Width => Math.Abs(this.Max.X - this.Min.X); /// /// Height of this bounding box (MaxY - MinY) /// - public double Height => this.MaxY - this.MinY; + public double Height => Math.Abs(this.Max.Y - this.Min.Y); /// /// Depth of this bounding box (MaxZ - MinZ) /// - public double Depth => this.MaxZ - this.MinZ; + public double Depth => Math.Abs(this.Max.Z - this.Min.Z); /// /// Min X, Y, Z /// - public Vector3 Min { get; } + public virtual Vector3 Min { get; } /// /// Max X, Y, Z /// - public Vector3 Max { get; } + public virtual Vector3 Max { get; } + + /// + /// Create a new instance of AABB + /// + protected AABB(Vector3 a, Vector3 b) + { + var min = a.Clone(); + var max = b.Clone(); + + min.Set(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y), Math.Min(a.Z, b.Z)); + max.Set(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y), Math.Max(a.Z, b.Z)); + + this.Min = min; + this.Max = max; + } /// /// Creates a new AABB /// - /// - /// - /// - /// - /// - /// public AABB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { if (minX > maxX) @@ -83,69 +63,15 @@ public AABB(double minX, double minY, double minZ, double maxX, double maxY, dou if (minZ > maxZ) (maxZ, minZ) = (minZ, maxZ); - this.Min = new Vector3(minX, minY, minZ); - this.Max = new Vector3(maxX, maxY, maxZ); - } - - - /// - /// Deflate this bounding box by , , - /// Mutates this instance. - /// - /// - /// - /// - /// - public AABB Deflate(double x, double y, double z) - { - this.Min.Add(x, y, z); - this.Max.Add(-x, -y, -z); - - return this; - } - - /// - /// Expand this bounding box by x, y, z - /// - public AABB Expand(double x, double y, double z) - { - if (x > 0) - this.Max.X += x; - else this.Min.X += x; - - if (y > 0) - this.Max.Y += y; - else this.Min.Y += y; - - if (z > 0) - this.Max.Z += z; - else this.Min.Z += z; - - return this; - } - - /// - /// Offset this bounding box by , , . - /// Mutates this instance. - /// - /// - /// - /// - /// - public AABB Offset(double x, double y, double z) - { - this.Min.Add(x, y, z); - this.Max.Add(x, y, z); - - return this; + this.Min = new MutableVector3(minX, minY, minZ); + this.Max = new MutableVector3(maxX, maxY, maxZ); } /// /// Returns a clone of this instance. /// - /// - public AABB Clone() - => new AABB(this.MinX, this.MinY, this.MinZ, this.MaxX, this.MaxY, this.MaxZ); + public MutableAABB Clone() + => new MutableAABB(this.Min.X, this.Min.Y, this.Min.Z, this.Max.X, this.Max.Y, this.Max.Z); /// /// Whether this bounding box and the other bounding box intersect. @@ -154,9 +80,9 @@ public AABB Clone() /// public bool Intersects(AABB other) { - return this.MaxX > other.MinX && this.MinX < other.MaxX - && this.MaxY > other.MinY && this.MinY < other.MaxY - && this.MaxZ > other.MinZ && this.MinZ < other.MaxZ; + return this.Max.X > other.Min.X && this.Min.X < other.Max.X + && this.Max.Y > other.Min.Y && this.Min.Y < other.Max.Y + && this.Max.Z > other.Min.Z && this.Min.Z < other.Max.Z; } /// @@ -167,9 +93,9 @@ public bool Intersects(AABB other) [Pure] public bool Contains(Vector3 point) { - return this.MinX <= point.X && this.MaxX > point.X - && this.MinY <= point.Y && this.MaxY > point.Y - && this.MinZ <= point.Z && this.MaxZ > point.Z; + return this.Min.X <= point.X && this.Max.X > point.X + && this.Min.Y <= point.Y && this.Max.Y > point.Y + && this.Min.Z <= point.Z && this.Max.Z > point.Z; } /// @@ -183,12 +109,12 @@ public bool IntersectsLine(Vector3 origin, Vector3 direction) { direction = direction.Normalized(); - var tMinX = (this.MinX - origin.X) / direction.X; - var tMaxX = (this.MaxX - origin.X) / direction.X; - var tMinY = (this.MinY - origin.Y) / direction.Y; - var tMaxY = (this.MaxY - origin.Y) / direction.Y; - var tMinZ = (this.MinZ - origin.Z) / direction.Z; - var tMaxZ = (this.MaxZ - origin.Z) / direction.Z; + var tMinX = (this.Min.X - origin.X) / direction.X; + var tMaxX = (this.Max.X - origin.X) / direction.X; + var tMinY = (this.Min.Y - origin.Y) / direction.Y; + var tMaxY = (this.Max.Y - origin.Y) / direction.Y; + var tMinZ = (this.Min.Z - origin.Z) / direction.Z; + var tMaxZ = (this.Max.Z - origin.Z) / direction.Z; var tMin = Math.Max(Math.Max(Math.Min(tMinX, tMaxX), Math.Min(tMinY, tMaxY)), Math.Min(tMinZ, tMaxZ)); var tMax = Math.Min(Math.Min(Math.Max(tMinX, tMaxX), Math.Max(tMinY, tMaxY)), Math.Max(tMinZ, tMaxZ)); @@ -254,3 +180,68 @@ public double CalculateMaxOffset(AABB other, Axis axis, double displacement) public override string ToString() => $"AABB ({Min} -> {Max})"; } + +public class MutableAABB : AABB +{ + /// + public override MutableVector3 Min { get; } + + /// + public override MutableVector3 Max { get; } + + + /// + public MutableAABB(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) : base(minX, minY, minZ, maxX, maxY, maxZ) + { + this.Min = (MutableVector3)base.Min; + this.Max = (MutableVector3)base.Max; + } + + /// + /// Deflate this bounding box by , , + /// Mutates this instance. + /// + public AABB Deflate(double x, double y, double z) + { + this.Min.Add(x, y, z); + this.Max.Add(-x, -y, -z); + + return this; + } + + /// + /// Expand this bounding box by x, y, z + /// + public AABB Expand(double x, double y, double z) + { + if (x > 0) + this.Max.Add(x, 0, 0); + else this.Min.Add(x, 0, 0); + + if (y > 0) + this.Max.Add(0, y, 0); + else this.Min.Add(0, y, 0); + + if (z > 0) + this.Max.Add(0, 0, z); + else this.Min.Add(0, 0, z); + + return this; + } + + /// + /// Offset this bounding box by , , . + /// Mutates this instance. + /// + /// + /// + /// + /// + public AABB Offset(double x, double y, double z) + { + this.Min.Add(x, y, z); + this.Max.Add(x, y, z); + + return this; + } +} diff --git a/MineSharp.Core/Geometry/Vector3.cs b/MineSharp.Core/Geometry/Vector3.cs index fbf0fca8..85a2e4e9 100644 --- a/MineSharp.Core/Geometry/Vector3.cs +++ b/MineSharp.Core/Geometry/Vector3.cs @@ -53,236 +53,104 @@ public class Vector3(double x, double y, double z) /// /// The X coordinate /// - public double X { get; set; } = x; + public double X { get; protected set; } = x; /// /// The Y coordinate /// - public double Y { get; set; } = y; + public double Y { get; protected set; } = y; /// /// The Z coordinate /// - public double Z { get; set; } = z; - - /// - /// Component-wise vector addition. - /// - /// - /// this - public Vector3 Add(Vector3 other) - { - this.X += other.X; - this.Y += other.Y; - this.Z += other.Z; - - return this; - } - - /// - /// Component-wise vector addition - /// - /// - /// - /// - /// this - public Vector3 Add(double x, double y, double z) - { - this.X += x; - this.Y += y; - this.Z += z; - - return this; - } + public double Z { get; protected set; } = z; /// /// Returns a new Vector with the added /// - /// - /// [Pure] - public Vector3 Plus(Vector3 other) - { - return new Vector3( - this.X + other.X, - this.Y + other.Y, - this.Z + other.Z); - } + public MutableVector3 Plus(Vector3 other) + => this.Clone().Add(other); /// - /// Component-wise vector subtraction. + /// Returns a new Vector with the added /// - /// - public Vector3 Subtract(Vector3 other) - { - this.X -= other.X; - this.Y -= other.Y; - this.Z -= other.Z; - - return this; - } - - /// - /// Component-wise vector subtraction. - /// - /// - /// - /// - public Vector3 Subtract(double x, double y, double z) - { - this.X -= x; - this.Y -= y; - this.Z -= z; - - return this; - } + public MutableVector3 Plus(double x, double y, double z) + => this.Clone().Add(x, y, z); /// /// Returns a new Vector with subtracted /// - /// - /// [Pure] - public Vector3 Minus(Vector3 other) - { - return new Vector3( - this.X - other.X, - this.Y - other.Y, - this.Z - other.Z); - } - + public MutableVector3 Minus(Vector3 other) + => this.Clone().Subtract(other); + /// /// Returns a new Vector with subtracted /// - /// - /// - /// - /// [Pure] - public Vector3 Minus(double x, double y, double z) - { - return new Vector3( - this.X - x, - this.Y - y, - this.Z - z); - } - - /// - /// Component-wise vector multiplication. - /// - /// - public Vector3 Multiply(Vector3 other) - { - this.X *= other.X; - this.Y *= other.Y; - this.Z *= other.Z; - - return this; - } + public MutableVector3 Minus(double x, double y, double z) + => this.Clone().Subtract(x, y, z); /// /// Returns a new Vector3 multiplied by /// /// [Pure] - public Vector3 Multiplied(Vector3 other) + public MutableVector3 Multiplied(Vector3 other) => this.Clone().Multiply(other); - /// - /// Component-wise vector division. - /// - /// - public Vector3 Divide(Vector3 other) - { - this.X /= other.X; - this.Y /= other.Y; - this.Z /= other.Z; - - return this; - } - /// /// Returns a new Vector3 divided by /// /// /// [Pure] - public Vector3 Divided(Vector3 other) + public MutableVector3 Divided(Vector3 other) => this.Clone().Divide(other); - /// - /// Scale this vector by a scalar - /// - /// - public void Scale(double scalar) - { - this.X *= scalar; - this.Y *= scalar; - this.Z *= scalar; - } - /// /// Returns a new Vector which was scaled by /// /// /// [Pure] - public Vector3 Scaled(double scalar) - { - var vec = this.Clone(); - vec.Scale(scalar); - return vec; - } + public MutableVector3 Scaled(double scalar) + => this.Clone().Scale(scalar); /// - /// Floor all values of this vector + /// Return a new Vector3 with all values floored /// - /// this - public Vector3 Floor() - { - this.X = Math.Floor(this.X); - this.Y = Math.Floor(this.Y); - this.Z = Math.Floor(this.Z); - - return this; - } - + [Pure] + public MutableVector3 Floored() + => this.Clone().Floor(); + /// - /// Return a new Vector3 with all values floored + /// Returns a new normalized instance of this vector /// /// [Pure] - public Vector3 Floored() - { - return this.Clone().Floor(); - } + public MutableVector3 Normalized() + => this.Clone().Normalize(); /// - /// Returns the length of this vector. + /// Calculates the length of this vector. /// - /// [Pure] public double Length() - { - return Math.Sqrt(this.LengthSquared()); - } + => Math.Sqrt(this.LengthSquared()); /// - /// Returns the squared length of this vector instance + /// Calculates the squared length of this vector instance /// - /// [Pure] public double LengthSquared() - { - return this.X * this.X + this.Y * this.Y + this.Z * this.Z; - } + => this.X * this.X + this.Y * this.Y + this.Z * this.Z; /// - /// Returns the horizontal squared length of this vector + /// Calculates the horizontal squared length of this vector /// - /// - /// [Pure] public double HorizontalDistanceToSquared(Vector3 other) { @@ -292,15 +160,13 @@ public double HorizontalDistanceToSquared(Vector3 other) } /// - /// Returns the distance to the vector. + /// Calculates the distance to the vector. /// /// /// [Pure] public double DistanceTo(Vector3 other) - { - return this.Minus(other).Length(); - } + => this.Minus(other).Length(); /// /// Returns the squared distance to the vector @@ -309,47 +175,15 @@ public double DistanceTo(Vector3 other) /// The distance squared. [Pure] public double DistanceToSquared(Vector3 other) - { - var diff = this.Minus(other); - return diff.X * diff.X + - diff.Y * diff.Y + - diff.Z * diff.Z; - } - - /// - /// Normalizes this vector instance - /// - public void Normalize() - { - var length = this.Length(); - - var scale = length == 0 - ? 0 - : 1 / length; - this.X *= scale; - this.Y *= scale; - this.Z *= scale; - } - - /// - /// Returns a new normalized instance of this vector - /// - /// - [Pure] - public Vector3 Normalized() - { - var clone = this.Clone(); - clone.Normalize(); - return clone; - } + => this.Minus(other).LengthSquared(); /// /// Returns this vector cloned /// /// [Pure] - public Vector3 Clone() - => new Vector3(this.X, this.Y, this.Z); + public MutableVector3 Clone() + => new MutableVector3(this.X, this.Y, this.Z); /// public override string ToString() @@ -375,8 +209,6 @@ public override int GetHashCode() /// /// Returns a new Position from this vector /// - /// - /// public static explicit operator Position(Vector3 x) => new Position(x.X, x.Y, x.Z); /// @@ -448,3 +280,152 @@ public override int GetHashCode() public static Vector3 operator /(Vector3 a, Vector3 b) => a.Divided(b); } + +/// +/// A mutable Vector3 +/// +public class MutableVector3 : Vector3 +{ + /// + /// Create a new instance of MutableVector3 + /// + public MutableVector3(double x, double y, double z) : base(x, y, z) + { } + + /// + /// Set x y z coordinates + /// + public MutableVector3 Set(double x, double y, double z) + { + this.X = x; + this.Y = y; + this.Z = z; + + return this; + } + + /// + /// Set x z coordinates + /// + public MutableVector3 Set(double x, double z) + { + this.X = x; + this.Z = z; + + return this; + } + + /// + /// Set x coordinate + /// + public MutableVector3 SetX(double x) + => this.Set(x, this.Y, this.Z); + + /// + /// Set y coordinate + /// + public MutableVector3 SetY(double y) + => this.Set(this.X, y, this.Z); + + /// + /// Set z coordinate + /// + public MutableVector3 SetZ(double z) + => this.Set(this.X, this.Y, z); + + /// + /// Component-wise vector addition + /// + public MutableVector3 Add(double x, double y, double z) + { + this.X += x; + this.Y += y; + this.Z += z; + + return this; + } + + /// + public MutableVector3 Add(Vector3 other) + => this.Add(other.X, other.Y, other.Z); + + /// + /// Component-wise vector subtraction. + /// + public MutableVector3 Subtract(double x, double y, double z) + { + this.X -= x; + this.Y -= y; + this.Z -= z; + + return this; + } + + /// + public MutableVector3 Subtract(Vector3 other) + => this.Subtract(other.X, other.Y, other.Z); + + /// + /// Component-wise vector multiplication. + /// + public MutableVector3 Multiply(double x, double y, double z) + { + this.X *= x; + this.Y *= y; + this.Z *= z; + + return this; + } + + /// + public MutableVector3 Multiply(Vector3 other) + => this.Multiply(other.X, other.Y, other.Z); + + /// + /// Component-wise vector division. + /// + public MutableVector3 Divide(double x, double y, double z) + { + this.X /= x; + this.Y /= y; + this.Z /= z; + + return this; + } + + /// + public MutableVector3 Divide(Vector3 other) + => this.Divide(other.X, other.Y, other.Z); + + /// + /// Scale this vector by a scalar + /// + public MutableVector3 Scale(double scalar) + => this.Multiply(scalar, scalar, scalar); + + /// + /// Floor all values of this vector + /// + public MutableVector3 Floor() + { + this.X = Math.Floor(this.X); + this.Y = Math.Floor(this.Y); + this.Z = Math.Floor(this.Z); + + return this; + } + + /// + /// Normalizes this vector instance + /// + public MutableVector3 Normalize() + { + var length = this.Length(); + + var scale = length == 0 + ? 0 + : 1 / length; + + return this.Scale(scale); + } +}