From 89c2ae40f9660d3f1b4195d40bd028fe8f8aff46 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Tue, 15 Dec 2015 23:32:37 +1100 Subject: [PATCH] Fix not being able to slide up small blocks with height < slab height (Thanks Empy), now use actual model's collision size instead of the default humanoid collision size, closes #110. --- .../2D/Screens/BlockSelectScreen.cs | 1 - ClassicalSharp/Entities/Entity.cs | 24 ++++++++---- ClassicalSharp/Entities/LocalPlayer.cs | 15 ++++--- ClassicalSharp/Entities/PhysicsEntity.cs | 39 ++++++++++++------- ClassicalSharp/Generator/Noise.cs | 5 +-- ClassicalSharp/Model/BlockModel.cs | 31 ++++++++++----- ClassicalSharp/Model/SpiderModel.cs | 1 - 7 files changed, 72 insertions(+), 44 deletions(-) diff --git a/ClassicalSharp/2D/Screens/BlockSelectScreen.cs b/ClassicalSharp/2D/Screens/BlockSelectScreen.cs index bfc87d59d..5a8bc0b83 100644 --- a/ClassicalSharp/2D/Screens/BlockSelectScreen.cs +++ b/ClassicalSharp/2D/Screens/BlockSelectScreen.cs @@ -140,7 +140,6 @@ namespace ClassicalSharp { int index = 0; SplitUppercase( origName, ref index ); normalNames[i] = buffer.ToString(); - Console.WriteLine( buffer.ToString() ); } } diff --git a/ClassicalSharp/Entities/Entity.cs b/ClassicalSharp/Entities/Entity.cs index beea68d28..44529f29a 100644 --- a/ClassicalSharp/Entities/Entity.cs +++ b/ClassicalSharp/Entities/Entity.cs @@ -38,9 +38,13 @@ namespace ClassicalSharp { /// Returns the size of the model that is used for collision detection. public virtual Vector3 CollisionSize { - get { return new Vector3( 8/16f, 28.5f/16f, 8/16f ); - //Model.CollisionSize; TODO: for non humanoid models - } + get { UpdateModel(); return Model.CollisionSize; } + } + + void UpdateModel() { + BlockModel model = Model as BlockModel; + if( model != null ) + model.CalcState( byte.Parse( ModelName ) ); } /// Bounding box of the model that collision detection @@ -103,9 +107,7 @@ namespace ClassicalSharp { /// bounding box of this entity are lava or still lava. protected bool TouchesAnyLava() { BoundingBox bounds = CollisionBounds.Expand( liqExpand ); - // Even though we collide with lava 3 blocks above our feet, vanilla client thinks - // that we do not.. so we have to maintain compatibility here. - bounds.Max.Y -= 4/16f; + AdjustLiquidTestBounds( ref bounds ); return TouchesAny( bounds, b => b == (byte)Block.Lava || b == (byte)Block.StillLava ); } @@ -121,9 +123,17 @@ namespace ClassicalSharp { /// bounding box of this entity are water or still water. protected bool TouchesAnyWater() { BoundingBox bounds = CollisionBounds.Expand( liqExpand ); - bounds.Max.Y -= 4/16f; + AdjustLiquidTestBounds( ref bounds ); return TouchesAny( bounds, b => b == (byte)Block.Water || b == (byte)Block.StillWater ); } + + void AdjustLiquidTestBounds( ref BoundingBox bounds ) { + // Even though we collide with lava 3 blocks above our feet, vanilla client thinks + // that we do not.. so we have to maintain compatibility here. + float height = bounds.Max.Y - bounds.Min.Y; + const float pHeight = (28.5f - 4f)/16f; + bounds.Max.Y = bounds.Min.Y + Math.Min( height, pHeight ); + } } } \ No newline at end of file diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs index f2989efb3..417709ec1 100644 --- a/ClassicalSharp/Entities/LocalPlayer.cs +++ b/ClassicalSharp/Entities/LocalPlayer.cs @@ -165,26 +165,25 @@ namespace ClassicalSharp { } if( !jumping ) { - canLiquidJump = false; - return; + canLiquidJump = false; return; } bool touchWater = TouchesAnyWater(); bool touchLava = TouchesAnyLava(); + Console.WriteLine( touchWater ); 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.Max.Y = bounds.Min.Y = bodyY; - bool liquidBody = TouchesAny( bounds, StandardLiquid ); - bounds.Max.Y = bounds.Min.Y = headY; - bool liquidHead = 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 && !(liquidBody || liquidHead) - && (Position.Y % 1 >= 0.4); + bool pastJumpPoint = liquidFeet && !liquidRest && (Position.Y % 1 >= 0.4); if( !pastJumpPoint ) { canLiquidJump = true; Velocity.Y += speeding ? 0.08f : 0.04f; diff --git a/ClassicalSharp/Entities/PhysicsEntity.cs b/ClassicalSharp/Entities/PhysicsEntity.cs index f3cdfc0f9..908f58ade 100644 --- a/ClassicalSharp/Entities/PhysicsEntity.cs +++ b/ClassicalSharp/Entities/PhysicsEntity.cs @@ -85,7 +85,7 @@ namespace ClassicalSharp { 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 @@ -160,27 +160,17 @@ namespace ClassicalSharp { ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) { float yDist = blockBB.Max.Y - entityBB.Min.Y; if( yDist > 0 && yDist <= StepSize + 0.01f ) { - // Adjust entity bounding box to include the block being tested BoundingBox adjFinalBB = finalBB; adjFinalBB.Min.X = Math.Min( finalBB.Min.X, blockBB.Min.X + Adjustment ); adjFinalBB.Max.X = Math.Max( finalBB.Max.X, blockBB.Max.X - Adjustment ); - adjFinalBB.Min.Y = (float)Math.Ceiling( blockBB.Max.Y ) + Adjustment; + adjFinalBB.Min.Y = blockBB.Max.Y + Adjustment; adjFinalBB.Max.Y = adjFinalBB.Min.Y + size.Y; adjFinalBB.Min.Z = Math.Min( finalBB.Min.Z, blockBB.Min.Z + Adjustment ); adjFinalBB.Max.Z = Math.Max( finalBB.Max.Z, blockBB.Max.Z - Adjustment ); - Vector3I min = Vector3I.Floor( adjFinalBB.Min ); - Vector3I max = Vector3I.Floor( adjFinalBB.Max ); - for( int x = min.X; x <= max.X; x++ ) { - for( int y = min.Y; y <= max.Y; y++ ) { - for( int z = min.Z; z <= max.Z; z++ ) { - if( info.CollideType[GetPhysicsBlockId( x, y, z )] == BlockCollideType.Solid ) - return false; - } - } - } - + if( !CanSlideThrough( ref adjFinalBB ) ) + return false; Position.Y = blockBB.Max.Y + Adjustment; onGround = true; ClipY( ref size, ref entityBB, ref entityExtentBB ); @@ -189,6 +179,27 @@ namespace ClassicalSharp { 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.CollideType[GetPhysicsBlockId( x, y, z )] == BlockCollideType.Solid ) + return false; + } + return true; + } + void ClipX( ref Vector3 size, ref BoundingBox entityBB, ref BoundingBox entityExtentBB ) { Velocity.X = 0; entityBB.Min.X = entityExtentBB.Min.X = Position.X - size.X / 2; diff --git a/ClassicalSharp/Generator/Noise.cs b/ClassicalSharp/Generator/Noise.cs index 6de73366a..c09e096bf 100644 --- a/ClassicalSharp/Generator/Noise.cs +++ b/ClassicalSharp/Generator/Noise.cs @@ -14,9 +14,7 @@ namespace ClassicalSharp.Generator { public sealed class ImprovedNoise : Noise { public ImprovedNoise( Random rnd ) { - // make a random initial permutation based on rnd's seed, - // shuffle using fisher-yates - + // shuffle randomly using fisher-yates for( int i = 0; i < 256; i++ ) p[i] = (byte)i; @@ -28,7 +26,6 @@ namespace ClassicalSharp.Generator { p[i + 256] = p[i]; } - // TODO: need to half this maybe? public override double Compute( double x, double y ) { int xFloor = x >= 0 ? (int)x : (int)x - 1; int yFloor = y >= 0 ? (int)y : (int)y - 1; diff --git a/ClassicalSharp/Model/BlockModel.cs b/ClassicalSharp/Model/BlockModel.cs index bcce00bb4..bd14567c9 100644 --- a/ClassicalSharp/Model/BlockModel.cs +++ b/ClassicalSharp/Model/BlockModel.cs @@ -10,8 +10,9 @@ namespace ClassicalSharp.Model { byte block = (byte)Block.Air; float blockHeight; TerrainAtlas1D atlas; - const float adjust = 0.1f, extent = 0.5f; + const float extent = 0.5f, adjust = 0.5f/16f; bool bright; + Vector3 minBB, maxBB; public BlockModel( Game game ) : base( game ) { } @@ -30,13 +31,27 @@ namespace ClassicalSharp.Model { } public override Vector3 CollisionSize { - get { return new Vector3( 1 - adjust, blockHeight - adjust, 1 - adjust ); } + get { return (maxBB - minBB) - new Vector3( adjust ); } } public override BoundingBox PickingBounds { get { return new BoundingBox( -extent, 0f, -extent, extent, blockHeight, extent ); } } + public void CalcState( byte block ) { + if( block == 0 ) { + blockHeight = 1; + bright = false; + minBB = Vector3.Zero; + maxBB = Vector3.One; + } else { + blockHeight = game.BlockInfo.Height[block]; + bright = game.BlockInfo.FullBright[block]; + minBB = game.BlockInfo.MinBB[block]; + maxBB = game.BlockInfo.MaxBB[block]; + } + } + int lastTexId = -1; protected override void DrawPlayerModel( Player p ) { // TODO: using 'is' is ugly, but means we can avoid creating @@ -49,14 +64,12 @@ namespace ClassicalSharp.Model { } else { block = Byte.Parse( p.ModelName ); } - if( block == 0 ) { - blockHeight = 1; + + CalcState( block ); + if( block == 0 ) return; - } lastTexId = -1; - blockHeight = game.BlockInfo.Height[block]; atlas = game.TerrainAtlas1D; - bright = game.BlockInfo.FullBright[block]; if( game.BlockInfo.IsSprite[block] ) { SpriteXQuad( TileSide.Right, true ); @@ -135,7 +148,7 @@ namespace ClassicalSharp.Model { float p1, p2; if( firstPart ) { // Need to break into two quads for when drawing a sprite model in hand. - rec.U1 = 0.5f; p1 = -5.5f/16; p2 = 0.0f/16; + rec.U1 = 0.5f; p1 = -5.5f/16; p2 = 0.0f/16; } else { rec.U2 = 0.5f; p1 = 0.0f/16; p2 = 5.5f/16; } @@ -155,7 +168,7 @@ namespace ClassicalSharp.Model { float x1, x2, z1, z2; if( firstPart ) { - rec.U1 = 0; rec.U2 = 0.5f; x1 = -5.5f/16; + rec.U1 = 0; rec.U2 = 0.5f; x1 = -5.5f/16; x2 = 0.0f/16; z1 = 5.5f/16; z2 = 0.0f/16; } else { rec.U1 = 0.5f; rec.U2 = 1f; x1 = 0.0f/16; diff --git a/ClassicalSharp/Model/SpiderModel.cs b/ClassicalSharp/Model/SpiderModel.cs index e7bab0b56..54b351534 100644 --- a/ClassicalSharp/Model/SpiderModel.cs +++ b/ClassicalSharp/Model/SpiderModel.cs @@ -50,7 +50,6 @@ namespace ClassicalSharp.Model { DrawPart( Link ); DrawPart( End ); - // TODO: leg animations float rotX = (float)(Math.Sin( p.walkTime ) * p.swing * Math.PI); float rotZ = (float)(Math.Cos( p.walkTime * 2 ) * p.swing * Math.PI / 16f); float rotY = (float)(Math.Sin( p.walkTime * 2 ) * p.swing * Math.PI / 32f);