diff --git a/ClassicalSharp/2D/Screens/FpsScreen.cs b/ClassicalSharp/2D/Screens/FpsScreen.cs
index 19995d693..ce5f25540 100644
--- a/ClassicalSharp/2D/Screens/FpsScreen.cs
+++ b/ClassicalSharp/2D/Screens/FpsScreen.cs
@@ -137,10 +137,10 @@ namespace ClassicalSharp.Gui {
bool speeding, halfSpeeding, noclip, fly;
int lastZoomFov;
void UpdateHackState( bool force ) {
- LocalPlayer p = game.LocalPlayer;
- if( force || p.speeding != speeding || p.halfSpeeding != halfSpeeding || p.noClip != noclip ||
- p.flying != fly || game.ZoomFieldOfView != lastZoomFov ) {
- speeding = p.speeding; halfSpeeding = p.halfSpeeding; noclip = p.noClip; fly = p.flying;
+ HacksComponent hacks = game.LocalPlayer.Hacks;
+ if( force || hacks.Speeding != speeding || hacks.HalfSpeeding != halfSpeeding || hacks.Noclip != noclip ||
+ hacks.Flying != fly || game.ZoomFieldOfView != lastZoomFov ) {
+ speeding = hacks.Speeding; halfSpeeding = hacks.HalfSpeeding; noclip = hacks.Noclip; fly = hacks.Flying;
lastZoomFov = game.ZoomFieldOfView;
int index = 0;
text.Clear();
diff --git a/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs b/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs
index 0ebc49e55..98c9ba017 100644
--- a/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs
+++ b/ClassicalSharp/2D/Screens/Menu/HacksSettingsScreen.cs
@@ -31,7 +31,7 @@ namespace ClassicalSharp.Gui {
Make2( -1, 0, "Jump height", OnWidgetClick,
g => g.LocalPlayer.JumpHeight.ToString( "F3" ),
- (g, v) => g.LocalPlayer.CalculateJumpVelocity( Single.Parse( v ) ) ),
+ (g, v) => g.LocalPlayer.physics.CalculateJumpVelocity( Single.Parse( v ) ) ),
MakeBool( -1, 50, "Double jump", OptionsKey.DoubleJump,
OnWidgetClick, g => g.LocalPlayer.Hacks.DoubleJump,
diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj
index 27ab04fed..555c6969d 100644
--- a/ClassicalSharp/ClassicalSharp.csproj
+++ b/ClassicalSharp/ClassicalSharp.csproj
@@ -150,13 +150,13 @@
+
-
@@ -170,7 +170,7 @@
-
+
diff --git a/ClassicalSharp/Entities/Components/CollisionsComponent.cs b/ClassicalSharp/Entities/Components/CollisionsComponent.cs
new file mode 100644
index 000000000..d48674c9f
--- /dev/null
+++ b/ClassicalSharp/Entities/Components/CollisionsComponent.cs
@@ -0,0 +1,331 @@
+// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
+using System;
+using OpenTK;
+
+namespace ClassicalSharp.Entities {
+
+ /// Entity component that performs collision detection.
+ public sealed class CollisionsComponent {
+
+ Game game;
+ Entity entity;
+ BlockInfo info;
+ public CollisionsComponent( Game game, Entity entity ) {
+ this.game = game;
+ this.entity = entity;
+ info = game.BlockInfo;
+ }
+
+ internal bool hitYMax, collideX, collideY, collideZ;
+
+ /// Constant offset used to avoid floating point roundoff errors.
+ public const float Adjustment = 0.001f;
+
+ public byte GetPhysicsBlockId( int x, int y, int z ) {
+ if( x < 0 || x >= game.World.Width || z < 0 ||
+ z >= game.World.Length || y < 0 ) return (byte)Block.Bedrock;
+
+ if( y >= game.World.Height ) return (byte)Block.Air;
+ return game.World.GetBlock( x, y, z );
+ }
+
+ bool GetBoundingBox( byte block, int x, int y, int z, ref BoundingBox box ) {
+ if( info.Collide[block] != CollideType.Solid ) return false;
+ Add( x, y, z, ref info.MinBB[block], ref box.Min );
+ Add( x, y, z, ref info.MaxBB[block], ref box.Max );
+ return true;
+ }
+
+ static void Add( int x, int y, int z, ref Vector3 offset, ref Vector3 target ) {
+ target.X = x + offset.X;
+ target.Y = y + offset.Y;
+ target.Z = z + offset.Z;
+ }
+
+
+ // TODO: test for corner cases, and refactor this.
+ internal void MoveAndWallSlide() {
+ if( entity.Velocity == Vector3.Zero ) return;
+ Vector3 size = entity.CollisionSize;
+ BoundingBox entityBB, entityExtentBB;
+ int count = 0;
+ FindReachableBlocks( ref count, ref size, out entityBB, out entityExtentBB );
+ CollideWithReachableBlocks( count, ref size, ref entityBB, ref entityExtentBB );
+ }
+
+ void FindReachableBlocks( ref int count, ref Vector3 size,
+ out BoundingBox entityBB, out BoundingBox entityExtentBB ) {
+ Vector3 vel = entity.Velocity;
+ Vector3 pos = entity.Position;
+ entityBB = new BoundingBox(
+ pos.X - size.X / 2, pos.Y, pos.Z - size.Z / 2,
+ pos.X + size.X / 2, pos.Y + size.Y, pos.Z + size.Z / 2
+ );
+
+ // Exact maximum extent the entity can reach, and the equivalent map coordinates.
+ entityExtentBB = new BoundingBox(
+ vel.X < 0 ? entityBB.Min.X + vel.X : entityBB.Min.X,
+ vel.Y < 0 ? entityBB.Min.Y + vel.Y : entityBB.Min.Y,
+ vel.Z < 0 ? entityBB.Min.Z + vel.Z : entityBB.Min.Z,
+ vel.X > 0 ? entityBB.Max.X + vel.X : entityBB.Max.X,
+ vel.Y > 0 ? entityBB.Max.Y + vel.Y : entityBB.Max.Y,
+ vel.Z > 0 ? entityBB.Max.Z + vel.Z : entityBB.Max.Z
+ );
+ Vector3I min = Vector3I.Floor( entityExtentBB.Min );
+ Vector3I max = Vector3I.Floor( entityExtentBB.Max );
+
+ int elements = (max.X + 1 - min.X) * (max.Y + 1 - min.Y) * (max.Z + 1 - min.Z);
+ if( elements > stateCache.Length ) {
+ stateCache = new State[elements];
+ }
+
+ BoundingBox blockBB = default( BoundingBox );
+ // Order loops so that we minimise cache misses
+ for( int y = min.Y; y <= max.Y; y++ )
+ for( int z = min.Z; z <= max.Z; z++ )
+ for( int x = min.X; x <= max.X; x++ )
+ {
+ byte blockId = GetPhysicsBlockId( x, y, z );
+ if( !GetBoundingBox( blockId, x, y, z, ref blockBB ) ) continue;
+ if( !entityExtentBB.Intersects( blockBB ) ) continue; // necessary for non whole blocks. (slabs)
+
+ float tx = 0, ty = 0, tz = 0;
+ CalcTime( ref vel, ref entityBB, ref blockBB, out tx, out ty, out tz );
+ if( tx > 1 || ty > 1 || tz > 1 ) continue;
+ float tSquared = tx * tx + ty * ty + tz * tz;
+ stateCache[count++] = new State( x, y, z, blockId, tSquared );
+ }
+ }
+
+ void CollideWithReachableBlocks( int count, ref Vector3 size,
+ ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
+ bool wasOn = entity.onGround;
+ entity.onGround = false;
+ if( count > 0 )
+ QuickSort( stateCache, 0, count - 1 );
+ collideX = false; collideY = false; collideZ = false;
+ BoundingBox blockBB = default(BoundingBox);
+
+ for( int i = 0; i < count; i++ ) {
+ State state = stateCache[i];
+ Vector3 blockPos = new Vector3( state.X >> 3, state.Y >> 3, state.Z >> 3 );
+ int block = (state.X & 0x7) | (state.Y & 0x7) << 3 | (state.Z & 0x7) << 6;
+ blockBB.Min = blockPos + info.MinBB[block];
+ blockBB.Max = blockPos + info.MaxBB[block];
+ if( !entityExtentBB.Intersects( blockBB ) ) continue;
+
+ float tx = 0, ty = 0, tz = 0;
+ CalcTime( ref entity.Velocity, ref entityBB, ref blockBB, out tx, out ty, out tz );
+ if( tx > 1 || ty > 1 || tz > 1 )
+ Utils.LogDebug( "t > 1 in physics calculation.. this shouldn't have happened." );
+ BoundingBox finalBB = entityBB.Offset( entity.Velocity * new Vector3( tx, ty, tz ) );
+
+ // if we have hit the bottom of a block, we need to change the axis we test first.
+ if( hitYMax ) {
+ if( finalBB.Min.Y + Adjustment >= blockBB.Max.Y )
+ ClipYMax( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
+ else if( finalBB.Max.Y - Adjustment <= blockBB.Min.Y )
+ ClipYMin( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
+ else if( finalBB.Min.X + Adjustment >= blockBB.Max.X )
+ ClipXMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Max.X - Adjustment <= blockBB.Min.X )
+ ClipXMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Min.Z + Adjustment >= blockBB.Max.Z )
+ ClipZMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Max.Z - Adjustment <= blockBB.Min.Z )
+ ClipZMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ continue;
+ }
+
+ // if flying or falling, test the horizontal axes first.
+ if( finalBB.Min.X + Adjustment >= blockBB.Max.X )
+ ClipXMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Max.X - Adjustment <= blockBB.Min.X )
+ ClipXMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Min.Z + Adjustment >= blockBB.Max.Z )
+ ClipZMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Max.Z - Adjustment <= blockBB.Min.Z )
+ ClipZMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
+ else if( finalBB.Min.Y + Adjustment >= blockBB.Max.Y )
+ ClipYMax( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
+ else if( finalBB.Max.Y - Adjustment <= blockBB.Min.Y )
+ ClipYMin( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
+ }
+ }
+
+ void ClipXMin( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
+ BoundingBox finalBB, ref BoundingBox entityExtentBB, ref Vector3 size ) {
+ if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB ) ) {
+ entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment;
+ ClipX( ref size, ref entityBB, ref entityExtentBB );
+ }
+ }
+
+ void ClipXMax( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
+ BoundingBox finalBB, ref BoundingBox entityExtentBB, ref Vector3 size ) {
+ if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB ) ) {
+ entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment;
+ ClipX( ref size, ref entityBB, ref entityExtentBB );
+ }
+ }
+
+ void ClipZMax( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
+ BoundingBox finalBB, ref BoundingBox entityExtentBB, ref Vector3 size ) {
+ if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB ) ) {
+ entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment;
+ ClipZ( ref size, ref entityBB, ref entityExtentBB );
+ }
+ }
+
+ void ClipZMin( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
+ BoundingBox finalBB, ref BoundingBox extentBB, ref Vector3 size ) {
+ if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref extentBB ) ) {
+ entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment;
+ ClipZ( ref size, ref entityBB, ref extentBB );
+ }
+ }
+
+ void ClipYMin( ref BoundingBox blockBB, ref BoundingBox entityBB,
+ ref BoundingBox extentBB, ref Vector3 size ) {
+ entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment;
+ ClipY( ref size, ref entityBB, ref extentBB );
+ hitYMax = false;
+ }
+
+ void ClipYMax( ref BoundingBox blockBB, ref BoundingBox entityBB,
+ ref BoundingBox extentBB, ref Vector3 size ) {
+ entity.Position.Y = blockBB.Max.Y + Adjustment;
+ entity.onGround = true;
+ ClipY( ref size, ref entityBB, ref extentBB );
+ hitYMax = true;
+ }
+
+ bool DidSlide( BoundingBox blockBB, ref Vector3 size, BoundingBox finalBB,
+ ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
+ float yDist = blockBB.Max.Y - entityBB.Min.Y;
+ if( yDist > 0 && yDist <= entity.StepSize + 0.01f ) {
+ float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z;
+ blockBB.Min.X = Math.Max( blockBB.Min.X, blockBB.Max.X - size.X / 2 );
+ blockBB.Max.X = Math.Min( blockBB.Max.X, blockXMin + size.X / 2 );
+ blockBB.Min.Z = Math.Max( blockBB.Min.Z, blockBB.Max.Z - size.Z / 2 );
+ blockBB.Max.Z = Math.Min( blockBB.Max.Z, blockZMin + size.Z / 2 );
+
+ BoundingBox adjBB = finalBB;
+ adjBB.Min.X = Math.Min( finalBB.Min.X, blockBB.Min.X + Adjustment );
+ adjBB.Max.X = Math.Max( finalBB.Max.X, blockBB.Max.X - Adjustment );
+ adjBB.Min.Y = blockBB.Max.Y + Adjustment;
+ adjBB.Max.Y = adjBB.Min.Y + size.Y;
+ adjBB.Min.Z = Math.Min( finalBB.Min.Z, blockBB.Min.Z + Adjustment );
+ adjBB.Max.Z = Math.Max( finalBB.Max.Z, blockBB.Max.Z - Adjustment );
+
+ if( !CanSlideThrough( ref adjBB ) )
+ return false;
+ entity.Position.Y = blockBB.Max.Y + Adjustment;
+ entity.onGround = true;
+ ClipY( ref size, ref entityBB, ref entityExtentBB );
+ return true;
+ }
+ return false;
+ }
+
+ bool CanSlideThrough( ref BoundingBox adjFinalBB ) {
+ Vector3I bbMin = Vector3I.Floor( adjFinalBB.Min );
+ Vector3I bbMax = Vector3I.Floor( adjFinalBB.Max );
+
+ for( int y = bbMin.Y; y <= bbMax.Y; y++ )
+ for( int z = bbMin.Z; z <= bbMax.Z; z++ )
+ for( int x = bbMin.X; x <= bbMax.X; x++ )
+ {
+ byte block = GetPhysicsBlockId( x, y, z );
+ Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
+ Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];
+
+ BoundingBox blockBB = new BoundingBox( min, max );
+ if( !blockBB.Intersects( adjFinalBB ) )
+ continue;
+ if( info.Collide[GetPhysicsBlockId( x, y, z )] == CollideType.Solid )
+ return false;
+ }
+ return true;
+ }
+
+ void ClipX( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
+ entity.Velocity.X = 0;
+ entityBB.Min.X = entityExtentBB.Min.X = entity.Position.X - size.X / 2;
+ entityBB.Max.X = entityExtentBB.Max.X = entity.Position.X + size.X / 2;
+ collideX = true;
+ }
+
+ void ClipY( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
+ entity.Velocity.Y = 0;
+ entityBB.Min.Y = entityExtentBB.Min.Y = entity.Position.Y;
+ entityBB.Max.Y = entityExtentBB.Max.Y = entity.Position.Y + size.Y;
+ collideY = true;
+ }
+
+ void ClipZ( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
+ entity.Velocity.Z = 0;
+ entityBB.Min.Z = entityExtentBB.Min.Z = entity.Position.Z - size.Z / 2;
+ entityBB.Max.Z = entityExtentBB.Max.Z = entity.Position.Z + size.Z / 2;
+ collideZ = true;
+ }
+
+ static void CalcTime( ref Vector3 vel, ref BoundingBox entityBB, ref BoundingBox blockBB,
+ out float tx, out float ty, out float tz ) {
+ float dx = vel.X > 0 ? blockBB.Min.X - entityBB.Max.X : entityBB.Min.X - blockBB.Max.X;
+ float dy = vel.Y > 0 ? blockBB.Min.Y - entityBB.Max.Y : entityBB.Min.Y - blockBB.Max.Y;
+ float dz = vel.Z > 0 ? blockBB.Min.Z - entityBB.Max.Z : entityBB.Min.Z - blockBB.Max.Z;
+
+ tx = vel.X == 0 ? float.PositiveInfinity : Math.Abs( dx / vel.X );
+ ty = vel.Y == 0 ? float.PositiveInfinity : Math.Abs( dy / vel.Y );
+ tz = vel.Z == 0 ? float.PositiveInfinity : Math.Abs( dz / vel.Z );
+
+ if( entityBB.XIntersects( blockBB ) ) tx = 0;
+ if( entityBB.YIntersects( blockBB ) ) ty = 0;
+ if( entityBB.ZIntersects( blockBB ) ) tz = 0;
+ }
+
+
+ struct State {
+ public int X, Y, Z;
+ public float tSquared;
+
+ public State( int x, int y, int z, byte block, float tSquared ) {
+ X = x << 3; Y = y << 3; Z = z << 3;
+ X |= (block & 0x07);
+ Y |= (block & 0x38) >> 3;
+ Z |= (block & 0xC0) >> 6;
+ this.tSquared = tSquared;
+ }
+ }
+ static State[] stateCache = new State[0];
+
+ static void QuickSort( State[] keys, int left, int right ) {
+ while( left < right ) {
+ int i = left, j = right;
+ float pivot = keys[(i + j) / 2].tSquared;
+ // partition the list
+ while( i <= j ) {
+ while( pivot > keys[i].tSquared ) i++;
+ while( pivot < keys[j].tSquared ) j--;
+
+ if( i <= j ) {
+ State key = keys[i]; keys[i] = keys[j]; keys[j] = key;
+ i++; j--;
+ }
+ }
+
+ // recurse into the smaller subset
+ if( j - left <= right - i ) {
+ if( left < j )
+ QuickSort( keys, left, j );
+ left = i;
+ } else {
+ if( i < right )
+ QuickSort( keys, i, right );
+ right = j;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ClassicalSharp/Entities/Components/HacksComponent.cs b/ClassicalSharp/Entities/Components/HacksComponent.cs
index 96ae54d3e..22ad64052 100644
--- a/ClassicalSharp/Entities/Components/HacksComponent.cs
+++ b/ClassicalSharp/Entities/Components/HacksComponent.cs
@@ -27,43 +27,45 @@ namespace ClassicalSharp.Entities {
/// Whether the player has allowed hacks usage as an option.
/// Note that all 'can use X' set by the server override this.
- public bool Enabled = true;
-
+ public bool Enabled = true;
/// Whether the player is allowed to use any type of hacks.
- public bool CanAnyHacks = true;
-
+ public bool CanAnyHacks = true;
/// Whether the player is allowed to use the types of cameras that use third person.
- public bool CanUseThirdPersonCamera = true;
-
+ public bool CanUseThirdPersonCamera = true;
/// Whether the player is allowed to increase its speed beyond the normal walking speed.
- public bool CanSpeed = true;
-
+ public bool CanSpeed = true;
/// Whether the player is allowed to fly in the world.
- public bool CanFly = true;
-
+ public bool CanFly = true;
/// Whether the player is allowed to teleport to their respawn coordinates.
- public bool CanRespawn = true;
-
+ public bool CanRespawn = true;
/// Whether the player is allowed to pass through all blocks.
- public bool CanNoclip = true;
-
+ public bool CanNoclip = true;
/// Whether the player is allowed to use pushback block placing.
- public bool CanPushbackBlocks = true;
-
+ public bool CanPushbackBlocks = true;
/// Whether the player is allowed to see all entity name tags.
- public bool CanSeeAllNames = true;
+ public bool CanSeeAllNames = true;
+ /// Whether the player is allowed to double jump.
+ public bool CanDoubleJump = true;
+ /// Maximum speed the entity can move at horizontally when CanSpeed is false.
+ public float MaxSpeedMultiplier = 1;
/// Whether the player should slide after letting go of movement buttons in noclip.
- public bool NoclipSlide = true;
-
+ public bool NoclipSlide = true;
/// Whether the player has allowed the usage of fast double jumping abilities.
public bool DoubleJump = false;
- /// Whether the player is allowed to double jump.
- public bool CanDoubleJump = true;
-
- /// Maximum speed the entity can move at horizontally when CanSpeed is false.
- public float MaxSpeedMultiplier = 1;
+ /// Whether the player currently has noclip on.
+ public bool Noclip;
+ /// Whether the player currently has fly mode active.
+ public bool Flying;
+ /// Whether the player is currently flying upwards.
+ public bool FlyingUp;
+ /// Whether the player is currently flying downwards.
+ public bool FlyingDown;
+ /// Whether the player is currently walking at base speed * speed multiplier.
+ public bool Speeding;
+ /// Whether the player is currently walking at base speed * 0.5 * speed multiplier.
+ public bool HalfSpeeding;
/// Parses hack flags specified in the motd and/or name of the server.
/// Recognises +/-hax, +/-fly, +/-noclip, +/-speed, +/-respawn, +/-ophax, and horspeed=xyz
@@ -124,5 +126,16 @@ namespace ClassicalSharp.Entities {
inv.CanPlace[(int)Block.StillLava] = value == 0x64;
CanSeeAllNames = value == 0x64;
}
+
+ /// Disables any hacks if their respective CanHackX value is set to false.
+ public void CheckHacksConsistency() {
+ if( !CanFly || !Enabled ) { Flying = false; FlyingDown = false; FlyingUp = false; }
+ if( !CanNoclip || !Enabled ) Noclip = false;
+ if( !CanSpeed || !Enabled ) { Speeding = false; HalfSpeeding = false; }
+ CanDoubleJump = CanAnyHacks && Enabled && CanSpeed;
+
+ if( !CanUseThirdPersonCamera || !Enabled )
+ game.CycleCamera();
+ }
}
}
\ No newline at end of file
diff --git a/ClassicalSharp/Entities/Components/PhysicsComponent.cs b/ClassicalSharp/Entities/Components/PhysicsComponent.cs
index 30bd41ff4..81bbd8840 100644
--- a/ClassicalSharp/Entities/Components/PhysicsComponent.cs
+++ b/ClassicalSharp/Entities/Components/PhysicsComponent.cs
@@ -7,325 +7,257 @@ namespace ClassicalSharp.Entities {
/// Entity component that performs collision detection.
public sealed class PhysicsComponent {
- Game game;
+ bool useLiquidGravity = false; // used by BlockDefinitions.
+ bool canLiquidJump = true;
+ internal bool firstJump, secondJump, jumping;
Entity entity;
+ Game game;
BlockInfo info;
+ internal float jumpVel = 0.42f, serverJumpVel = 0.42f;
+ internal HacksComponent hacks;
+ internal CollisionsComponent collisions;
+
public PhysicsComponent( Game game, Entity entity ) {
this.game = game;
this.entity = entity;
info = game.BlockInfo;
}
- internal bool hitYMax, collideX, collideY, collideZ;
-
- /// Constant offset used to avoid floating point roundoff errors.
- public const float Adjustment = 0.001f;
-
- public byte GetPhysicsBlockId( int x, int y, int z ) {
- if( x < 0 || x >= game.World.Width || z < 0 ||
- z >= game.World.Length || y < 0 ) return (byte)Block.Bedrock;
-
- if( y >= game.World.Height ) return (byte)Block.Air;
- return game.World.GetBlock( x, y, z );
- }
-
- bool GetBoundingBox( byte block, int x, int y, int z, ref BoundingBox box ) {
- if( info.Collide[block] != CollideType.Solid ) return false;
- Add( x, y, z, ref info.MinBB[block], ref box.Min );
- Add( x, y, z, ref info.MaxBB[block], ref box.Max );
- return true;
- }
-
- static void Add( int x, int y, int z, ref Vector3 offset, ref Vector3 target ) {
- target.X = x + offset.X;
- target.Y = y + offset.Y;
- target.Z = z + offset.Z;
- }
-
-
- // TODO: test for corner cases, and refactor this.
- internal void MoveAndWallSlide() {
- if( entity.Velocity == Vector3.Zero ) return;
- Vector3 size = entity.CollisionSize;
- BoundingBox entityBB, entityExtentBB;
- int count = 0;
- FindReachableBlocks( ref count, ref size, out entityBB, out entityExtentBB );
- CollideWithReachableBlocks( count, ref size, ref entityBB, ref entityExtentBB );
- }
-
- void FindReachableBlocks( ref int count, ref Vector3 size,
- out BoundingBox entityBB, out BoundingBox entityExtentBB ) {
- Vector3 vel = entity.Velocity;
- Vector3 pos = entity.Position;
- entityBB = new BoundingBox(
- pos.X - size.X / 2, pos.Y, pos.Z - size.Z / 2,
- pos.X + size.X / 2, pos.Y + size.Y, pos.Z + size.Z / 2
- );
-
- // Exact maximum extent the entity can reach, and the equivalent map coordinates.
- entityExtentBB = new BoundingBox(
- vel.X < 0 ? entityBB.Min.X + vel.X : entityBB.Min.X,
- vel.Y < 0 ? entityBB.Min.Y + vel.Y : entityBB.Min.Y,
- vel.Z < 0 ? entityBB.Min.Z + vel.Z : entityBB.Min.Z,
- vel.X > 0 ? entityBB.Max.X + vel.X : entityBB.Max.X,
- vel.Y > 0 ? entityBB.Max.Y + vel.Y : entityBB.Max.Y,
- vel.Z > 0 ? entityBB.Max.Z + vel.Z : entityBB.Max.Z
- );
- Vector3I min = Vector3I.Floor( entityExtentBB.Min );
- Vector3I max = Vector3I.Floor( entityExtentBB.Max );
-
- int elements = (max.X + 1 - min.X) * (max.Y + 1 - min.Y) * (max.Z + 1 - min.Z);
- if( elements > stateCache.Length ) {
- stateCache = new State[elements];
+ public void UpdateVelocityState( float xMoving, float zMoving ) {
+ if( !hacks.NoclipSlide && (hacks.Noclip && xMoving == 0 && zMoving == 0) )
+ entity.Velocity = Vector3.Zero;
+ if( hacks.Flying || hacks.Noclip ) {
+ entity.Velocity.Y = 0; // eliminate the effect of gravity
+ int dir = (hacks.FlyingUp || jumping) ? 1 : (hacks.FlyingDown ? -1 : 0);
+
+ entity.Velocity.Y += 0.12f * dir;
+ if( hacks.Speeding && hacks.CanSpeed ) entity.Velocity.Y += 0.12f * dir;
+ if( hacks.HalfSpeeding && hacks.CanSpeed ) entity.Velocity.Y += 0.06f * dir;
+ } else if( jumping && entity.TouchesAnyRope() && entity.Velocity.Y > 0.02f ) {
+ entity.Velocity.Y = 0.02f;
}
- BoundingBox blockBB = default( BoundingBox );
- // Order loops so that we minimise cache misses
- for( int y = min.Y; y <= max.Y; y++ )
- for( int z = min.Z; z <= max.Z; z++ )
- for( int x = min.X; x <= max.X; x++ )
- {
- byte blockId = GetPhysicsBlockId( x, y, z );
- if( !GetBoundingBox( blockId, x, y, z, ref blockBB ) ) continue;
- if( !entityExtentBB.Intersects( blockBB ) ) continue; // necessary for non whole blocks. (slabs)
-
- float tx = 0, ty = 0, tz = 0;
- CalcTime( ref vel, ref entityBB, ref blockBB, out tx, out ty, out tz );
- if( tx > 1 || ty > 1 || tz > 1 ) continue;
- float tSquared = tx * tx + ty * ty + tz * tz;
- stateCache[count++] = new State( x, y, z, blockId, tSquared );
+ if( !jumping ) {
+ canLiquidJump = false; return;
}
- }
-
- void CollideWithReachableBlocks( int count, ref Vector3 size,
- ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
- bool wasOn = entity.onGround;
- entity.onGround = false;
- if( count > 0 )
- QuickSort( stateCache, 0, count - 1 );
- collideX = false; collideY = false; collideZ = false;
- BoundingBox blockBB = default(BoundingBox);
-
- for( int i = 0; i < count; i++ ) {
- State state = stateCache[i];
- Vector3 blockPos = new Vector3( state.X >> 3, state.Y >> 3, state.Z >> 3 );
- int block = (state.X & 0x7) | (state.Y & 0x7) << 3 | (state.Z & 0x7) << 6;
- blockBB.Min = blockPos + info.MinBB[block];
- blockBB.Max = blockPos + info.MaxBB[block];
- if( !entityExtentBB.Intersects( blockBB ) ) continue;
+
+ bool touchWater = entity.TouchesAnyWater();
+ bool touchLava = entity.TouchesAnyLava();
+ if( touchWater || touchLava ) {
+ BoundingBox bounds = entity.CollisionBounds;
+ int feetY = Utils.Floor( bounds.Min.Y ), bodyY = feetY + 1;
+ int headY = Utils.Floor( bounds.Max.Y );
+ if( bodyY > headY ) bodyY = headY;
- float tx = 0, ty = 0, tz = 0;
- CalcTime( ref entity.Velocity, ref entityBB, ref blockBB, out tx, out ty, out tz );
- if( tx > 1 || ty > 1 || tz > 1 )
- Utils.LogDebug( "t > 1 in physics calculation.. this shouldn't have happened." );
- BoundingBox finalBB = entityBB.Offset( entity.Velocity * new Vector3( tx, ty, tz ) );
+ bounds.Max.Y = bounds.Min.Y = feetY;
+ bool liquidFeet = entity.TouchesAny( bounds, StandardLiquid );
+ bounds.Min.Y = Math.Min( bodyY, headY );
+ bounds.Max.Y = Math.Max( bodyY, headY );
+ bool liquidRest = entity.TouchesAny( bounds, StandardLiquid );
- // if we have hit the bottom of a block, we need to change the axis we test first.
- if( hitYMax ) {
- if( finalBB.Min.Y + Adjustment >= blockBB.Max.Y )
- ClipYMax( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
- else if( finalBB.Max.Y - Adjustment <= blockBB.Min.Y )
- ClipYMin( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
- else if( finalBB.Min.X + Adjustment >= blockBB.Max.X )
- ClipXMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Max.X - Adjustment <= blockBB.Min.X )
- ClipXMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Min.Z + Adjustment >= blockBB.Max.Z )
- ClipZMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Max.Z - Adjustment <= blockBB.Min.Z )
- ClipZMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- continue;
+ bool pastJumpPoint = liquidFeet && !liquidRest && (entity.Position.Y % 1 >= 0.4);
+ if( !pastJumpPoint ) {
+ canLiquidJump = true;
+ entity.Velocity.Y += 0.04f;
+ if( hacks.Speeding && hacks.CanSpeed ) entity.Velocity.Y += 0.04f;
+ if( hacks.HalfSpeeding && hacks.CanSpeed ) entity.Velocity.Y += 0.02f;
+ } else if( pastJumpPoint ) {
+ // either A) jump bob in water B) climb up solid on side
+ if( canLiquidJump || (collisions.collideX || collisions.collideZ) )
+ entity.Velocity.Y += touchLava ? 0.20f : 0.10f;
+ canLiquidJump = false;
}
-
- // if flying or falling, test the horizontal axes first.
- if( finalBB.Min.X + Adjustment >= blockBB.Max.X )
- ClipXMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Max.X - Adjustment <= blockBB.Min.X )
- ClipXMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Min.Z + Adjustment >= blockBB.Max.Z )
- ClipZMax( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Max.Z - Adjustment <= blockBB.Min.Z )
- ClipZMin( ref blockBB, ref entityBB, wasOn, finalBB, ref entityExtentBB, ref size );
- else if( finalBB.Min.Y + Adjustment >= blockBB.Max.Y )
- ClipYMax( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
- else if( finalBB.Max.Y - Adjustment <= blockBB.Min.Y )
- ClipYMin( ref blockBB, ref entityBB, ref entityExtentBB, ref size );
+ } else if( useLiquidGravity ) {
+ entity.Velocity.Y += 0.04f;
+ if( hacks.Speeding && hacks.CanSpeed ) entity.Velocity.Y += 0.04f;
+ if( hacks.HalfSpeeding && hacks.CanSpeed ) entity.Velocity.Y += 0.02f;
+ canLiquidJump = false;
+ } else if( entity.TouchesAnyRope() ) {
+ entity.Velocity.Y += (hacks.Speeding && hacks.CanSpeed) ? 0.15f : 0.10f;
+ canLiquidJump = false;
+ } else if( entity.onGround ) {
+ DoNormalJump();
}
}
- void ClipXMin( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
- BoundingBox finalBB, ref BoundingBox entityExtentBB, ref Vector3 size ) {
- if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB ) ) {
- entity.Position.X = blockBB.Min.X - size.X / 2 - Adjustment;
- ClipX( ref size, ref entityBB, ref entityExtentBB );
+ public void DoNormalJump() {
+ entity.Velocity.Y = jumpVel;
+ if( hacks.Speeding && hacks.CanSpeed ) entity.Velocity.Y += jumpVel;
+ if( hacks.HalfSpeeding && hacks.CanSpeed ) entity.Velocity.Y += jumpVel / 2;
+ canLiquidJump = false;
+ }
+
+ bool StandardLiquid( byte block ) {
+ return info.Collide[block] == CollideType.SwimThrough;
+ }
+
+ static Vector3 waterDrag = new Vector3( 0.8f, 0.8f, 0.8f ),
+ lavaDrag = new Vector3( 0.5f, 0.5f, 0.5f ),
+ ropeDrag = new Vector3( 0.5f, 0.85f, 0.5f ),
+ normalDrag = new Vector3( 0.91f, 0.98f, 0.91f ),
+ airDrag = new Vector3( 0.6f, 1f, 0.6f );
+ const float liquidGrav = 0.02f, ropeGrav = 0.034f, normalGrav = 0.08f;
+
+ public void PhysicsTick( float xMoving, float zMoving ) {
+ if( hacks.Noclip ) entity.onGround = false;
+ float multiply = GetBaseMultiply( true );
+ float yMultiply = GetBaseMultiply( hacks.CanSpeed );
+ float modifier = LowestSpeedModifier();
+
+ float yMul = Math.Max( 1f, yMultiply / 5 ) * modifier;
+ float horMul = multiply * modifier;
+ if( !(hacks.Flying || hacks.Noclip) ) {
+ if( secondJump ) { horMul *= 93f; yMul *= 10f; }
+ else if( firstJump ) { horMul *= 46.5f; yMul *= 7.5f; }
}
- }
-
- void ClipXMax( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
- BoundingBox finalBB, ref BoundingBox entityExtentBB, ref Vector3 size ) {
- if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB ) ) {
- entity.Position.X = blockBB.Max.X + size.X / 2 + Adjustment;
- ClipX( ref size, ref entityBB, ref entityExtentBB );
+
+ if( entity.TouchesAnyWater() && !hacks.Flying && !hacks.Noclip ) {
+ MoveNormal( xMoving, zMoving, 0.02f * horMul, waterDrag, liquidGrav, yMul );
+ } else if( entity.TouchesAnyLava() && !hacks.Flying && !hacks.Noclip ) {
+ MoveNormal( xMoving, zMoving, 0.02f * horMul, lavaDrag, liquidGrav, yMul );
+ } else if( entity.TouchesAnyRope() && !hacks.Flying && !hacks.Noclip ) {
+ MoveNormal( xMoving, zMoving, 0.02f * 1.7f, ropeDrag, ropeGrav, yMul );
+ } else {
+ float factor = !(hacks.Flying || hacks.Noclip) && entity.onGround ? 0.1f : 0.02f;
+ float gravity = useLiquidGravity ? liquidGrav : normalGrav;
+ if( hacks.Flying || hacks.Noclip )
+ MoveFlying( xMoving, zMoving, factor * horMul, normalDrag, gravity, yMul );
+ else
+ MoveNormal( xMoving, zMoving, factor * horMul, normalDrag, gravity, yMul );
+
+ if( entity.BlockUnderFeet == Block.Ice && !(hacks.Flying || hacks.Noclip) ) {
+ // limit components to +-0.25f by rescaling vector to [-0.25, 0.25]
+ if( Math.Abs( entity.Velocity.X ) > 0.25f || Math.Abs( entity.Velocity.Z ) > 0.25f ) {
+ float scale = Math.Min(
+ Math.Abs( 0.25f / entity.Velocity.X ), Math.Abs( 0.25f / entity.Velocity.Z ) );
+ entity.Velocity.X *= scale;
+ entity.Velocity.Z *= scale;
+ }
+ } else if( entity.onGround || hacks.Flying ) {
+ entity.Velocity *= airDrag; // air drag or ground friction
+ }
}
+
+ if( entity.onGround ) { firstJump = false; secondJump = false; }
}
- void ClipZMax( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
- BoundingBox finalBB, ref BoundingBox entityExtentBB, ref Vector3 size ) {
- if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref entityExtentBB ) ) {
- entity.Position.Z = blockBB.Max.Z + size.Z / 2 + Adjustment;
- ClipZ( ref size, ref entityBB, ref entityExtentBB );
+ void AdjHeadingVelocity( float x, float z, float factor ) {
+ float dist = (float)Math.Sqrt( x * x + z * z );
+ if( dist < 0.00001f ) return;
+ if( dist < 1 ) dist = 1;
+
+ float multiply = factor / dist;
+ entity.Velocity += Utils.RotateY( x * multiply, 0, z * multiply, entity.HeadYawRadians );
+ }
+
+ void MoveFlying( float xMoving, float zMoving, float factor, Vector3 drag, float gravity, float yMul ) {
+ AdjHeadingVelocity( zMoving, xMoving, factor );
+ float yVel = (float)Math.Sqrt( entity.Velocity.X * entity.Velocity.X + entity.Velocity.Z * entity.Velocity.Z );
+ // make vertical speed the same as vertical speed.
+ if( (xMoving != 0 || zMoving != 0) && yVel > 0.001f ) {
+ entity.Velocity.Y = 0;
+ yMul = 1;
+ if( hacks.FlyingUp || jumping ) entity.Velocity.Y += yVel;
+ if( hacks.FlyingDown ) entity.Velocity.Y -= yVel;
}
+ Move( xMoving, zMoving, factor, drag, gravity, yMul );
}
- void ClipZMin( ref BoundingBox blockBB, ref BoundingBox entityBB, bool wasOn,
- BoundingBox finalBB, ref BoundingBox extentBB, ref Vector3 size ) {
- if( !wasOn || !DidSlide( blockBB, ref size, finalBB, ref entityBB, ref extentBB ) ) {
- entity.Position.Z = blockBB.Min.Z - size.Z / 2 - Adjustment;
- ClipZ( ref size, ref entityBB, ref extentBB );
+ void MoveNormal( float xMoving, float zMoving, float factor, Vector3 drag, float gravity, float yMul ) {
+ AdjHeadingVelocity( zMoving, xMoving, factor );
+ Move( xMoving, zMoving, factor, drag, gravity, yMul );
+ }
+
+ void Move( float xMoving, float zMoving, float factor, Vector3 drag, float gravity, float yMul ) {
+ entity.Velocity.Y *= yMul;
+ if( !hacks.Noclip )
+ collisions.MoveAndWallSlide();
+ entity.Position += entity.Velocity;
+
+ entity.Velocity.Y /= yMul;
+ entity.Velocity *= drag;
+ entity.Velocity.Y -= gravity;
+ }
+
+ float GetBaseMultiply( bool canSpeed ) {
+ float multiply = 0;
+ if( hacks.Flying || hacks.Noclip ) {
+ if( hacks.Speeding && canSpeed ) multiply += hacks.SpeedMultiplier * 8;
+ if( hacks.HalfSpeeding && canSpeed ) multiply += hacks.SpeedMultiplier * 8 / 2;
+ if( multiply == 0 ) multiply = 8f;
+ } else {
+ if( hacks.Speeding && canSpeed ) multiply += hacks.SpeedMultiplier;
+ if( hacks.HalfSpeeding && canSpeed ) multiply += hacks.SpeedMultiplier / 2;
+ if( multiply == 0 ) multiply = 1;
}
+ return hacks.CanSpeed ? multiply : Math.Min( multiply, hacks.MaxSpeedMultiplier );
}
- void ClipYMin( ref BoundingBox blockBB, ref BoundingBox entityBB,
- ref BoundingBox extentBB, ref Vector3 size ) {
- entity.Position.Y = blockBB.Min.Y - size.Y - Adjustment;
- ClipY( ref size, ref entityBB, ref extentBB );
- hitYMax = false;
+ const float inf = float.PositiveInfinity;
+ float LowestSpeedModifier() {
+ BoundingBox bounds = entity.CollisionBounds;
+ useLiquidGravity = false;
+ float baseModifier = LowestModifier( bounds, false );
+ bounds.Min.Y -= 0.5f/16f; // also check block standing on
+ float solidModifier = LowestModifier( bounds, true );
+
+ if( baseModifier == inf && solidModifier == inf ) return 1;
+ return baseModifier == inf ? solidModifier : baseModifier;
}
- void ClipYMax( ref BoundingBox blockBB, ref BoundingBox entityBB,
- ref BoundingBox extentBB, ref Vector3 size ) {
- entity.Position.Y = blockBB.Max.Y + Adjustment;
- entity.onGround = true;
- ClipY( ref size, ref entityBB, ref extentBB );
- hitYMax = true;
- }
-
- bool DidSlide( BoundingBox blockBB, ref Vector3 size, BoundingBox finalBB,
- ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
- float yDist = blockBB.Max.Y - entityBB.Min.Y;
- if( yDist > 0 && yDist <= entity.StepSize + 0.01f ) {
- float blockXMin = blockBB.Min.X, blockZMin = blockBB.Min.Z;
- blockBB.Min.X = Math.Max( blockBB.Min.X, blockBB.Max.X - size.X / 2 );
- blockBB.Max.X = Math.Min( blockBB.Max.X, blockXMin + size.X / 2 );
- blockBB.Min.Z = Math.Max( blockBB.Min.Z, blockBB.Max.Z - size.Z / 2 );
- blockBB.Max.Z = Math.Min( blockBB.Max.Z, blockZMin + size.Z / 2 );
-
- BoundingBox adjBB = finalBB;
- adjBB.Min.X = Math.Min( finalBB.Min.X, blockBB.Min.X + Adjustment );
- adjBB.Max.X = Math.Max( finalBB.Max.X, blockBB.Max.X - Adjustment );
- adjBB.Min.Y = blockBB.Max.Y + Adjustment;
- adjBB.Max.Y = adjBB.Min.Y + size.Y;
- adjBB.Min.Z = Math.Min( finalBB.Min.Z, blockBB.Min.Z + Adjustment );
- adjBB.Max.Z = Math.Max( finalBB.Max.Z, blockBB.Max.Z - Adjustment );
-
- if( !CanSlideThrough( ref adjBB ) )
- return false;
- entity.Position.Y = blockBB.Max.Y + Adjustment;
- entity.onGround = true;
- ClipY( ref size, ref entityBB, ref entityExtentBB );
- return true;
- }
- return false;
- }
-
- bool CanSlideThrough( ref BoundingBox adjFinalBB ) {
- Vector3I bbMin = Vector3I.Floor( adjFinalBB.Min );
- Vector3I bbMax = Vector3I.Floor( adjFinalBB.Max );
+ float LowestModifier( BoundingBox bounds, bool checkSolid ) {
+ Vector3I bbMin = Vector3I.Floor( bounds.Min );
+ Vector3I bbMax = Vector3I.Floor( bounds.Max );
+ float modifier = inf;
for( int y = bbMin.Y; y <= bbMax.Y; y++ )
for( int z = bbMin.Z; z <= bbMax.Z; z++ )
for( int x = bbMin.X; x <= bbMax.X; x++ )
{
- byte block = GetPhysicsBlockId( x, y, z );
+ byte block = game.World.SafeGetBlock( x, y, z );
+ if( block == 0 ) continue;
+ CollideType type = info.Collide[block];
+ if( type == CollideType.Solid && !checkSolid )
+ continue;
+
Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];
-
BoundingBox blockBB = new BoundingBox( min, max );
- if( !blockBB.Intersects( adjFinalBB ) )
- continue;
- if( info.Collide[GetPhysicsBlockId( x, y, z )] == CollideType.Solid )
- return false;
- }
- return true;
- }
-
- void ClipX( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
- entity.Velocity.X = 0;
- entityBB.Min.X = entityExtentBB.Min.X = entity.Position.X - size.X / 2;
- entityBB.Max.X = entityExtentBB.Max.X = entity.Position.X + size.X / 2;
- collideX = true;
- }
-
- void ClipY( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
- entity.Velocity.Y = 0;
- entityBB.Min.Y = entityExtentBB.Min.Y = entity.Position.Y;
- entityBB.Max.Y = entityExtentBB.Max.Y = entity.Position.Y + size.Y;
- collideY = true;
- }
-
- void ClipZ( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) {
- entity.Velocity.Z = 0;
- entityBB.Min.Z = entityExtentBB.Min.Z = entity.Position.Z - size.Z / 2;
- entityBB.Max.Z = entityExtentBB.Max.Z = entity.Position.Z + size.Z / 2;
- collideZ = true;
- }
-
- static void CalcTime( ref Vector3 vel, ref BoundingBox entityBB, ref BoundingBox blockBB,
- out float tx, out float ty, out float tz ) {
- float dx = vel.X > 0 ? blockBB.Min.X - entityBB.Max.X : entityBB.Min.X - blockBB.Max.X;
- float dy = vel.Y > 0 ? blockBB.Min.Y - entityBB.Max.Y : entityBB.Min.Y - blockBB.Max.Y;
- float dz = vel.Z > 0 ? blockBB.Min.Z - entityBB.Max.Z : entityBB.Min.Z - blockBB.Max.Z;
-
- tx = vel.X == 0 ? float.PositiveInfinity : Math.Abs( dx / vel.X );
- ty = vel.Y == 0 ? float.PositiveInfinity : Math.Abs( dy / vel.Y );
- tz = vel.Z == 0 ? float.PositiveInfinity : Math.Abs( dz / vel.Z );
-
- if( entityBB.XIntersects( blockBB ) ) tx = 0;
- if( entityBB.YIntersects( blockBB ) ) ty = 0;
- if( entityBB.ZIntersects( blockBB ) ) tz = 0;
- }
-
-
- struct State {
- public int X, Y, Z;
- public float tSquared;
-
- public State( int x, int y, int z, byte block, float tSquared ) {
- X = x << 3; Y = y << 3; Z = z << 3;
- X |= (block & 0x07);
- Y |= (block & 0x38) >> 3;
- Z |= (block & 0xC0) >> 6;
- this.tSquared = tSquared;
- }
- }
- static State[] stateCache = new State[0];
-
- static void QuickSort( State[] keys, int left, int right ) {
- while( left < right ) {
- int i = left, j = right;
- float pivot = keys[(i + j) / 2].tSquared;
- // partition the list
- while( i <= j ) {
- while( pivot > keys[i].tSquared ) i++;
- while( pivot < keys[j].tSquared ) j--;
-
- if( i <= j ) {
- State key = keys[i]; keys[i] = keys[j]; keys[j] = key;
- i++; j--;
- }
- }
+ if( !blockBB.Intersects( bounds ) ) continue;
- // recurse into the smaller subset
- if( j - left <= right - i ) {
- if( left < j )
- QuickSort( keys, left, j );
- left = i;
- } else {
- if( i < right )
- QuickSort( keys, i, right );
- right = j;
- }
+ modifier = Math.Min( modifier, info.SpeedMultiplier[block] );
+ if( block >= BlockInfo.CpeBlocksCount && type == CollideType.SwimThrough )
+ useLiquidGravity = true;
}
+ return modifier;
+ }
+
+ /// Calculates the jump velocity required such that when a client presses
+ /// the jump binding they will be able to jump up to the given height.
+ internal void CalculateJumpVelocity( float jumpHeight ) {
+ jumpVel = 0;
+ if( jumpHeight >= 256 ) jumpVel = 10.0f;
+ if( jumpHeight >= 512 ) jumpVel = 16.5f;
+ if( jumpHeight >= 768 ) jumpVel = 22.5f;
+
+ while( GetMaxHeight( jumpVel ) <= jumpHeight )
+ jumpVel += 0.001f;
+ }
+
+ public static double GetMaxHeight( float u ) {
+ // equation below comes from solving diff(x(t, u))= 0
+ // We only work in discrete timesteps, so test both rounded up and down.
+ double t = 49.49831645 * Math.Log( 0.247483075 * u + 0.9899323 );
+ return Math.Max( YPosAt( (int)t, u ), YPosAt( (int)t + 1, u ) );
+ }
+
+ static double YPosAt( int t, float u ) {
+ // v(t, u) = (4 + u) * (0.98^t) - 4, where u = initial velocity
+ // x(t, u) = Σv(t, u) from 0 to t (since we work in discrete timesteps)
+ // plugging into Wolfram Alpha gives 1 equation as
+ // (0.98^t) * (-49u - 196) - 4t + 50u + 196
+ double a = Math.Exp( -0.0202027 * t ); //~0.98^t
+ return a * ( -49 * u - 196 ) - 4 * t + 50 * u + 196;
}
}
}
\ No newline at end of file
diff --git a/ClassicalSharp/Entities/Entity.Bounds.cs b/ClassicalSharp/Entities/Entity.Bounds.cs
index 2a2310a10..ef7b6c553 100644
--- a/ClassicalSharp/Entities/Entity.Bounds.cs
+++ b/ClassicalSharp/Entities/Entity.Bounds.cs
@@ -60,7 +60,7 @@ namespace ClassicalSharp.Entities {
/// Determines whether any of the blocks that intersect the
/// bounding box of this entity are lava or still lava.
- protected bool TouchesAnyLava() {
+ public bool TouchesAnyLava() {
BoundingBox bounds = CollisionBounds.Expand( liqExpand );
AdjustLiquidTestBounds( ref bounds );
return TouchesAny( bounds,
@@ -69,7 +69,7 @@ namespace ClassicalSharp.Entities {
/// Determines whether any of the blocks that intersect the
/// bounding box of this entity are rope.
- protected bool TouchesAnyRope() {
+ public bool TouchesAnyRope() {
BoundingBox bounds = CollisionBounds;
bounds.Max.Y += 0.5f/16f;
return TouchesAny( bounds, b => b == (byte)Block.Rope );
@@ -77,7 +77,7 @@ namespace ClassicalSharp.Entities {
/// Determines whether any of the blocks that intersect the
/// bounding box of this entity are water or still water.
- protected bool TouchesAnyWater() {
+ public bool TouchesAnyWater() {
BoundingBox bounds = CollisionBounds.Expand( liqExpand );
AdjustLiquidTestBounds( ref bounds );
return TouchesAny( bounds,
diff --git a/ClassicalSharp/Entities/LocalPlayer.Physics.cs b/ClassicalSharp/Entities/LocalPlayer.Physics.cs
deleted file mode 100644
index 1bbf27951..000000000
--- a/ClassicalSharp/Entities/LocalPlayer.Physics.cs
+++ /dev/null
@@ -1,251 +0,0 @@
-// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT
-using System;
-using System.Drawing;
-using ClassicalSharp.Renderers;
-using OpenTK;
-using OpenTK.Input;
-
-namespace ClassicalSharp.Entities {
-
- public partial class LocalPlayer : Player {
-
- bool useLiquidGravity = false; // used by BlockDefinitions.
- bool canLiquidJump = true;
- bool firstJump = false, secondJump = false;
-
- void UpdateVelocityState( float xMoving, float zMoving ) {
- if( !Hacks.NoclipSlide && (noClip && xMoving == 0 && zMoving == 0) )
- Velocity = Vector3.Zero;
- if( flying || noClip ) {
- Velocity.Y = 0; // eliminate the effect of gravity
- int dir = (flyingUp || jumping) ? 1 : (flyingDown ? -1 : 0);
-
- Velocity.Y += 0.12f * dir;
- if( speeding && Hacks.CanSpeed ) Velocity.Y += 0.12f * dir;
- if( halfSpeeding && Hacks.CanSpeed ) Velocity.Y += 0.06f * dir;
- } else if( jumping && TouchesAnyRope() && Velocity.Y > 0.02f ) {
- Velocity.Y = 0.02f;
- }
-
- if( !jumping ) {
- canLiquidJump = false; return;
- }
-
- bool touchWater = TouchesAnyWater();
- bool touchLava = TouchesAnyLava();
- if( touchWater || touchLava ) {
- BoundingBox bounds = CollisionBounds;
- int feetY = Utils.Floor( bounds.Min.Y ), bodyY = feetY + 1;
- int headY = Utils.Floor( bounds.Max.Y );
- if( bodyY > headY ) bodyY = headY;
-
- bounds.Max.Y = bounds.Min.Y = feetY;
- bool liquidFeet = TouchesAny( bounds, StandardLiquid );
- bounds.Min.Y = Math.Min( bodyY, headY );
- bounds.Max.Y = Math.Max( bodyY, headY );
- bool liquidRest = TouchesAny( bounds, StandardLiquid );
-
- bool pastJumpPoint = liquidFeet && !liquidRest && (Position.Y % 1 >= 0.4);
- if( !pastJumpPoint ) {
- canLiquidJump = true;
- Velocity.Y += 0.04f;
- if( speeding && Hacks.CanSpeed ) Velocity.Y += 0.04f;
- if( halfSpeeding && Hacks.CanSpeed ) Velocity.Y += 0.02f;
- } else if( pastJumpPoint ) {
- // either A) jump bob in water B) climb up solid on side
- if( canLiquidJump || (physics.collideX || physics.collideZ) )
- Velocity.Y += touchLava ? 0.20f : 0.10f;
- canLiquidJump = false;
- }
- } else if( useLiquidGravity ) {
- Velocity.Y += 0.04f;
- if( speeding && Hacks.CanSpeed ) Velocity.Y += 0.04f;
- if( halfSpeeding && Hacks.CanSpeed ) Velocity.Y += 0.02f;
- canLiquidJump = false;
- } else if( TouchesAnyRope() ) {
- Velocity.Y += (speeding && Hacks.CanSpeed) ? 0.15f : 0.10f;
- canLiquidJump = false;
- } else if( onGround ) {
- DoNormalJump();
- }
- }
-
- void DoNormalJump() {
- Velocity.Y = jumpVel;
- if( speeding && Hacks.CanSpeed ) Velocity.Y += jumpVel;
- if( halfSpeeding && Hacks.CanSpeed ) Velocity.Y += jumpVel / 2;
- canLiquidJump = false;
- }
-
- bool StandardLiquid( byte block ) {
- return info.Collide[block] == CollideType.SwimThrough;
- }
-
- static Vector3 waterDrag = new Vector3( 0.8f, 0.8f, 0.8f ),
- lavaDrag = new Vector3( 0.5f, 0.5f, 0.5f ),
- ropeDrag = new Vector3( 0.5f, 0.85f, 0.5f ),
- normalDrag = new Vector3( 0.91f, 0.98f, 0.91f ),
- airDrag = new Vector3( 0.6f, 1f, 0.6f );
- const float liquidGrav = 0.02f, ropeGrav = 0.034f, normalGrav = 0.08f;
-
- void PhysicsTick( float xMoving, float zMoving ) {
- if( noClip ) onGround = false;
- float multiply = GetBaseMultiply( true );
- float yMultiply = GetBaseMultiply( Hacks.CanSpeed );
- float modifier = LowestSpeedModifier();
-
- float yMul = Math.Max( 1f, yMultiply / 5 ) * modifier;
- float horMul = multiply * modifier;
- if( !(flying || noClip) ) {
- if( secondJump ) { horMul *= 93f; yMul *= 10f; }
- else if( firstJump ) { horMul *= 46.5f; yMul *= 7.5f; }
- }
-
- if( TouchesAnyWater() && !flying && !noClip ) {
- MoveNormal( xMoving, zMoving, 0.02f * horMul, waterDrag, liquidGrav, yMul );
- } else if( TouchesAnyLava() && !flying && !noClip ) {
- MoveNormal( xMoving, zMoving, 0.02f * horMul, lavaDrag, liquidGrav, yMul );
- } else if( TouchesAnyRope() && !flying && !noClip ) {
- MoveNormal( xMoving, zMoving, 0.02f * 1.7f, ropeDrag, ropeGrav, yMul );
- } else {
- float factor = !(flying || noClip) && onGround ? 0.1f : 0.02f;
- float gravity = useLiquidGravity ? liquidGrav : normalGrav;
- if( flying || noClip )
- MoveFlying( xMoving, zMoving, factor * horMul, normalDrag, gravity, yMul );
- else
- MoveNormal( xMoving, zMoving, factor * horMul, normalDrag, gravity, yMul );
-
- if( BlockUnderFeet == Block.Ice && !(flying || noClip) ) {
- // limit components to +-0.25f by rescaling vector to [-0.25, 0.25]
- if( Math.Abs( Velocity.X ) > 0.25f || Math.Abs( Velocity.Z ) > 0.25f ) {
- float scale = Math.Min(
- Math.Abs( 0.25f / Velocity.X ), Math.Abs( 0.25f / Velocity.Z ) );
- Velocity.X *= scale;
- Velocity.Z *= scale;
- }
- } else if( onGround || flying ) {
- Velocity *= airDrag; // air drag or ground friction
- }
- }
- }
-
- void AdjHeadingVelocity( float x, float z, float factor ) {
- float dist = (float)Math.Sqrt( x * x + z * z );
- if( dist < 0.00001f ) return;
- if( dist < 1 ) dist = 1;
-
- float multiply = factor / dist;
- Velocity += Utils.RotateY( x * multiply, 0, z * multiply, HeadYawRadians );
- }
-
- void MoveFlying( float xMoving, float zMoving, float factor, Vector3 drag, float gravity, float yMul ) {
- AdjHeadingVelocity( zMoving, xMoving, factor );
- float yVel = (float)Math.Sqrt( Velocity.X * Velocity.X + Velocity.Z * Velocity.Z );
- // make vertical speed the same as vertical speed.
- if( (xMoving != 0 || zMoving != 0) && yVel > 0.001f ) {
- Velocity.Y = 0;
- yMul = 1;
- if( flyingUp || jumping ) Velocity.Y += yVel;
- if( flyingDown ) Velocity.Y -= yVel;
- }
- Move( xMoving, zMoving, factor, drag, gravity, yMul );
- }
-
- void MoveNormal( float xMoving, float zMoving, float factor, Vector3 drag, float gravity, float yMul ) {
- AdjHeadingVelocity( zMoving, xMoving, factor );
- Move( xMoving, zMoving, factor, drag, gravity, yMul );
- }
-
- void Move( float xMoving, float zMoving, float factor, Vector3 drag, float gravity, float yMul ) {
- Velocity.Y *= yMul;
- if( !noClip )
- physics.MoveAndWallSlide();
- Position += Velocity;
-
- Velocity.Y /= yMul;
- Velocity *= drag;
- Velocity.Y -= gravity;
- }
-
- float GetBaseMultiply( bool canSpeed ) {
- float multiply = 0;
- if( flying || noClip ) {
- if( speeding && canSpeed ) multiply += Hacks.SpeedMultiplier * 8;
- if( halfSpeeding && canSpeed ) multiply += Hacks.SpeedMultiplier * 8 / 2;
- if( multiply == 0 ) multiply = 8f;
- } else {
- if( speeding && canSpeed ) multiply += Hacks.SpeedMultiplier;
- if( halfSpeeding && canSpeed ) multiply += Hacks.SpeedMultiplier / 2;
- if( multiply == 0 ) multiply = 1;
- }
- return Hacks.CanSpeed ? multiply : Math.Min( multiply, Hacks.MaxSpeedMultiplier );
- }
-
- const float inf = float.PositiveInfinity;
- float LowestSpeedModifier() {
- BoundingBox bounds = CollisionBounds;
- useLiquidGravity = false;
- float baseModifier = LowestModifier( bounds, false );
- bounds.Min.Y -= 0.5f/16f; // also check block standing on
- float solidModifier = LowestModifier( bounds, true );
-
- if( baseModifier == inf && solidModifier == inf ) return 1;
- return baseModifier == inf ? solidModifier : baseModifier;
- }
-
- float LowestModifier( BoundingBox bounds, bool checkSolid ) {
- Vector3I bbMin = Vector3I.Floor( bounds.Min );
- Vector3I bbMax = Vector3I.Floor( bounds.Max );
- float modifier = inf;
-
- for( int y = bbMin.Y; y <= bbMax.Y; y++ )
- for( int z = bbMin.Z; z <= bbMax.Z; z++ )
- for( int x = bbMin.X; x <= bbMax.X; x++ )
- {
- byte block = game.World.SafeGetBlock( x, y, z );
- if( block == 0 ) continue;
- CollideType type = info.Collide[block];
- if( type == CollideType.Solid && !checkSolid )
- continue;
-
- Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
- Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];
- BoundingBox blockBB = new BoundingBox( min, max );
- if( !blockBB.Intersects( bounds ) ) continue;
-
- modifier = Math.Min( modifier, info.SpeedMultiplier[block] );
- if( block >= BlockInfo.CpeBlocksCount && type == CollideType.SwimThrough )
- useLiquidGravity = true;
- }
- return modifier;
- }
-
- /// Calculates the jump velocity required such that when a client presses
- /// the jump binding they will be able to jump up to the given height.
- internal void CalculateJumpVelocity( float jumpHeight ) {
- jumpVel = 0;
- if( jumpHeight >= 256 ) jumpVel = 10.0f;
- if( jumpHeight >= 512 ) jumpVel = 16.5f;
- if( jumpHeight >= 768 ) jumpVel = 22.5f;
-
- while( GetMaxHeight( jumpVel ) <= jumpHeight )
- jumpVel += 0.001f;
- }
-
- static double GetMaxHeight( float u ) {
- // equation below comes from solving diff(x(t, u))= 0
- // We only work in discrete timesteps, so test both rounded up and down.
- double t = 49.49831645 * Math.Log( 0.247483075 * u + 0.9899323 );
- return Math.Max( YPosAt( (int)t, u ), YPosAt( (int)t + 1, u ) );
- }
-
- static double YPosAt( int t, float u ) {
- // v(t, u) = (4 + u) * (0.98^t) - 4, where u = initial velocity
- // x(t, u) = Σv(t, u) from 0 to t (since we work in discrete timesteps)
- // plugging into Wolfram Alpha gives 1 equation as
- // (0.98^t) * (-49u - 196) - 4t + 50u + 196
- double a = Math.Exp( -0.0202027 * t ); //~0.98^t
- return a * ( -49 * u - 196 ) - 4 * t + 50 * u + 196;
- }
- }
-}
\ No newline at end of file
diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs
index ad0ddeaaf..23b94de5e 100644
--- a/ClassicalSharp/Entities/LocalPlayer.cs
+++ b/ClassicalSharp/Entities/LocalPlayer.cs
@@ -18,23 +18,26 @@ namespace ClassicalSharp.Entities {
/// reach to and interact/modify blocks in.
public float ReachDistance = 5f;
- internal float jumpVel = 0.42f, serverJumpVel = 0.42f;
/// Returns the height that the client can currently jump up to.
/// Note that when speeding is enabled the client is able to jump much further.
public float JumpHeight {
- get { return (float)GetMaxHeight( jumpVel ); }
+ get { return (float)PhysicsComponent.GetMaxHeight( physics.jumpVel ); }
}
internal float curWalkTime, curSwing;
- internal PhysicsComponent physics;
+ internal CollisionsComponent collisions;
public HacksComponent Hacks;
+ internal PhysicsComponent physics;
public LocalPlayer( Game game ) : base( game ) {
DisplayName = game.Username;
SkinName = game.Username;
SkinIdentifier = "skin_255";
- physics = new PhysicsComponent( game, this );
+ collisions = new CollisionsComponent( game, this );
Hacks = new HacksComponent( game, this );
+ physics = new PhysicsComponent( game, this );
+ physics.hacks = Hacks;
+ physics.collisions = collisions;
Hacks.SpeedMultiplier = Options.GetFloat( OptionsKey.Speed, 0.1f, 50, 10 );
Hacks.PushbackPlacing = !game.ClassicMode && Options.GetBool( OptionsKey.PushbackPlacing, false );
@@ -56,9 +59,8 @@ namespace ClassicalSharp.Entities {
bool wasOnGround = onGround;
HandleInput( ref xMoving, ref zMoving );
- UpdateVelocityState( xMoving, zMoving );
- PhysicsTick( xMoving, zMoving );
- if( onGround ) { firstJump = false; secondJump = false; }
+ physics.UpdateVelocityState( xMoving, zMoving );
+ physics.PhysicsTick( xMoving, zMoving );
nextPos = Position;
Position = lastPos;
@@ -146,34 +148,26 @@ namespace ClassicalSharp.Entities {
void HandleInput( ref float xMoving, ref float zMoving ) {
if( game.ScreenLockedInput ) {
- jumping = speeding = flyingUp = flyingDown = false;
+ physics.jumping = Hacks.Speeding = Hacks.FlyingUp = Hacks.FlyingDown = false;
} else {
if( game.IsKeyDown( KeyBinding.Forward ) ) xMoving -= 0.98f;
if( game.IsKeyDown( KeyBinding.Back ) ) xMoving += 0.98f;
if( game.IsKeyDown( KeyBinding.Left ) ) zMoving -= 0.98f;
if( game.IsKeyDown( KeyBinding.Right ) ) zMoving += 0.98f;
- jumping = game.IsKeyDown( KeyBinding.Jump );
- speeding = Hacks.Enabled && game.IsKeyDown( KeyBinding.Speed );
- halfSpeeding = Hacks.Enabled && game.IsKeyDown( KeyBinding.HalfSpeed );
- flyingUp = game.IsKeyDown( KeyBinding.FlyUp );
- flyingDown = game.IsKeyDown( KeyBinding.FlyDown );
+ physics.jumping = game.IsKeyDown( KeyBinding.Jump );
+ Hacks.Speeding = Hacks.Enabled && game.IsKeyDown( KeyBinding.Speed );
+ Hacks.HalfSpeeding = Hacks.Enabled && game.IsKeyDown( KeyBinding.HalfSpeed );
+ Hacks.FlyingUp = game.IsKeyDown( KeyBinding.FlyUp );
+ Hacks.FlyingDown = game.IsKeyDown( KeyBinding.FlyDown );
}
}
- internal bool jumping, speeding, halfSpeeding, flying, noClip, flyingDown, flyingUp;
-
/// Disables any hacks if their respective CanHackX value is set to false.
public void CheckHacksConsistency() {
- if( !Hacks.CanFly || !Hacks.Enabled ) { flying = false; flyingDown = false; flyingUp = false; }
- if( !Hacks.CanNoclip || !Hacks.Enabled ) noClip = false;
- if( !Hacks.CanSpeed || !Hacks.Enabled ) { speeding = false; halfSpeeding = false; }
- Hacks.CanDoubleJump = Hacks.CanAnyHacks && Hacks.Enabled && Hacks.CanSpeed;
-
- if( !Hacks.CanUseThirdPersonCamera || !Hacks.Enabled )
- game.CycleCamera();
+ Hacks.CheckHacksConsistency();
if( !Hacks.Enabled || !Hacks.CanAnyHacks || !Hacks.CanSpeed )
- jumpVel = serverJumpVel;
+ physics.jumpVel = physics.serverJumpVel;
}
internal Vector3 lastPos, nextPos;
@@ -248,17 +242,17 @@ namespace ClassicalSharp.Entities {
SpawnYaw = HeadYawDegrees;
SpawnPitch = PitchDegrees;
} else if( key == keys[KeyBinding.Fly] && Hacks.CanFly && Hacks.Enabled ) {
- flying = !flying;
+ Hacks.Flying = !Hacks.Flying;
} else if( key == keys[KeyBinding.NoClip] && Hacks.CanNoclip && Hacks.Enabled ) {
- if( noClip ) Velocity.Y = 0;
- noClip = !noClip;
- } else if( key == keys[KeyBinding.Jump] && !onGround && !(flying || noClip) ) {
- if( !firstJump && Hacks.CanDoubleJump && Hacks.DoubleJump ) {
- DoNormalJump();
- firstJump = true;
- } else if( !secondJump && Hacks.CanDoubleJump && Hacks.DoubleJump ) {
- DoNormalJump();
- secondJump = true;
+ if( Hacks.Noclip ) Velocity.Y = 0;
+ Hacks.Noclip = !Hacks.Noclip;
+ } else if( key == keys[KeyBinding.Jump] && !onGround && !(Hacks.Flying || Hacks.Noclip) ) {
+ if( !physics.firstJump && Hacks.CanDoubleJump && Hacks.DoubleJump ) {
+ physics.DoNormalJump();
+ physics.firstJump = true;
+ } else if( !physics.secondJump && Hacks.CanDoubleJump && Hacks.DoubleJump ) {
+ physics.DoNormalJump();
+ physics.secondJump = true;
}
} else {
return false;
@@ -282,10 +276,9 @@ namespace ClassicalSharp.Entities {
for ( int xx = minX; xx <= maxX; xx++ )
{
Vector3I coords = new Vector3I( P.X + xx, y + yy, P.Z + zz );
- byte block = physics.GetPhysicsBlockId( coords.X, coords.Y, coords.Z );
+ byte block = collisions.GetPhysicsBlockId( coords.X, coords.Y, coords.Z );
Vector3 min = info.MinBB[block] + (Vector3)coords;
Vector3 max = info.MaxBB[block] + (Vector3)coords;
- Console.WriteLine( min + "_" + max );
if( !bb.Intersects( new BoundingBox( min, max ) ) ) continue;
anyHit |= info.Collide[block] == CollideType.Solid;
}
diff --git a/ClassicalSharp/Game/InputHandler.cs b/ClassicalSharp/Game/InputHandler.cs
index cb7b2e3c5..b00de305b 100644
--- a/ClassicalSharp/Game/InputHandler.cs
+++ b/ClassicalSharp/Game/InputHandler.cs
@@ -123,7 +123,7 @@ namespace ClassicalSharp {
pos + game.BlockInfo.MaxBB[newBlock] );
BoundingBox localBB = game.LocalPlayer.CollisionBounds;
- if( game.LocalPlayer.noClip || !localBB.Intersects( blockBB ) ) return true;
+ if( game.LocalPlayer.Hacks.Noclip || !localBB.Intersects( blockBB ) ) return true;
HacksComponent hacks = game.LocalPlayer.Hacks;
if( hacks.CanPushbackBlocks && hacks.PushbackPlacing && hacks.Enabled )
return PushbackPlace( selected, blockBB );
@@ -163,7 +163,8 @@ namespace ClassicalSharp {
if( !validPos ) return false;
game.LocalPlayer.Position = newP;
- if( !game.LocalPlayer.noClip && game.LocalPlayer.TouchesAny( CannotPassThrough ) ) {
+ if( !game.LocalPlayer.Hacks.Noclip
+ && game.LocalPlayer.TouchesAny( CannotPassThrough ) ) {
game.LocalPlayer.Position = oldP;
return false;
}
diff --git a/ClassicalSharp/Math/Picking.cs b/ClassicalSharp/Math/Picking.cs
index 96e85de39..159146878 100644
--- a/ClassicalSharp/Math/Picking.cs
+++ b/ClassicalSharp/Math/Picking.cs
@@ -7,20 +7,20 @@ namespace ClassicalSharp {
public static class Picking {
- static RayCaster ray = new RayCaster();
+ static RayTracer tracer = new RayTracer();
/// Determines the picked block based on the given origin and direction vector.
/// Marks pickedPos as invalid if a block could not be found due to going outside map boundaries
/// or not being able to find a suitable candiate within the given reach distance.
public static void CalculatePickedBlock( Game game, Vector3 origin, Vector3 dir, float reach, PickedPos pickedPos ) {
- ray.SetRayData( origin, dir );
+ tracer.SetRayData( origin, dir );
World map = game.World;
BlockInfo info = game.BlockInfo;
float reachSquared = reach * reach;
int iterations = 0;
while( iterations < 10000 ) {
- int x = ray.X, y = ray.Y, z = ray.Z;
+ int x = tracer.X, y = tracer.Y, z = tracer.Z;
byte block = GetBlock( map, x, y, z, origin );
Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];
@@ -43,7 +43,7 @@ namespace ClassicalSharp {
return;
}
}
- ray.Step();
+ tracer.Step();
iterations++;
}
throw new InvalidOperationException( "did over 10000 iterations in CalculatePickedBlock(). " +
@@ -56,14 +56,14 @@ namespace ClassicalSharp {
pickedPos.IntersectPoint = origin + dir * reach;
return;
}
- ray.SetRayData( origin, dir );
+ tracer.SetRayData( origin, dir );
World map = game.World;
BlockInfo info = game.BlockInfo;
float reachSquared = reach * reach;
int iterations = 0;
while( iterations < 10000 ) {
- int x = ray.X, y = ray.Y, z = ray.Z;
+ int x = tracer.X, y = tracer.Y, z = tracer.Z;
byte block = GetBlock( map, x, y, z, origin );
Vector3 min = new Vector3( x, y, z ) + info.MinBB[block];
Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block];
@@ -102,7 +102,7 @@ namespace ClassicalSharp {
return;
}
}
- ray.Step();
+ tracer.Step();
iterations++;
}
throw new InvalidOperationException( "did over 10000 iterations in ClipCameraPos(). " +
diff --git a/ClassicalSharp/Math/RayCaster.cs b/ClassicalSharp/Math/RayTracer.cs
similarity index 96%
rename from ClassicalSharp/Math/RayCaster.cs
rename to ClassicalSharp/Math/RayTracer.cs
index 225978172..e22f23cc5 100644
--- a/ClassicalSharp/Math/RayCaster.cs
+++ b/ClassicalSharp/Math/RayTracer.cs
@@ -12,7 +12,7 @@ namespace ClassicalSharp {
// John Amanatides, Andrew Woo
// http://www.cse.yorku.ca/~amana/research/grid.pdf
// http://www.devmaster.net/articles/raytracing_series/A%20faster%20voxel%20traversal%20algorithm%20for%20ray%20tracing.pdf
- public sealed class RayCaster {
+ public sealed class RayTracer {
public int X, Y, Z;
Vector3I step, cellBoundary;
diff --git a/ClassicalSharp/Network/NetworkProcessor.CPE.cs b/ClassicalSharp/Network/NetworkProcessor.CPE.cs
index 22597d13e..6cfac542a 100644
--- a/ClassicalSharp/Network/NetworkProcessor.CPE.cs
+++ b/ClassicalSharp/Network/NetworkProcessor.CPE.cs
@@ -348,9 +348,9 @@ namespace ClassicalSharp.Net {
p.CheckHacksConsistency();
float jumpHeight = reader.ReadInt16() / 32f;
- if( jumpHeight < 0 ) p.jumpVel = 0.42f;
- else p.CalculateJumpVelocity( jumpHeight );
- p.serverJumpVel = p.jumpVel;
+ if( jumpHeight < 0 ) p.physics.jumpVel = 0.42f;
+ else p.physics.CalculateJumpVelocity( jumpHeight );
+ p.physics.serverJumpVel = p.physics.jumpVel;
game.Events.RaiseHackPermissionsChanged();
}
diff --git a/ClassicalSharp/Network/NetworkProcessor.cs b/ClassicalSharp/Network/NetworkProcessor.cs
index 455004dcd..69e76a3e0 100644
--- a/ClassicalSharp/Network/NetworkProcessor.cs
+++ b/ClassicalSharp/Network/NetworkProcessor.cs
@@ -66,6 +66,7 @@ namespace ClassicalSharp.Net {
if( (DateTime.UtcNow - lastPacket).TotalSeconds >= 20 )
CheckDisconnection( delta );
if( Disconnected ) return;
+ LocalPlayer player = game.LocalPlayer;
try {
reader.ReadPendingData();
@@ -76,15 +77,15 @@ namespace ClassicalSharp.Net {
return;
} catch {
throw;
- }
+ }
while( (reader.size - reader.index) > 0 ) {
byte opcode = reader.buffer[reader.index];
// Workaround for older D3 servers which wrote one byte too many for HackControl packets.
if( opcode == 0xFF && lastOpcode == PacketId.CpeHackControl ) {
reader.Skip( 1 );
- game.LocalPlayer.jumpVel = 0.42f; // assume default jump height
- game.LocalPlayer.serverJumpVel = game.LocalPlayer.jumpVel;
+ player.physics.jumpVel = 0.42f; // assume default jump height
+ player.physics.serverJumpVel = player.physics.jumpVel;
continue;
}
@@ -98,9 +99,8 @@ namespace ClassicalSharp.Net {
if( (reader.size - reader.index) < packetSizes[opcode] ) break;
ReadPacket( opcode );
}
- reader.RemoveProcessed();
- Player player = game.LocalPlayer;
+ reader.RemoveProcessed();
if( receivedFirstPosition ) {
SendPosition( player.Position, player.HeadYawDegrees, player.PitchDegrees );
}