From fb0fdce7abc2d1265ec7f465b59d1cbca3ae3f12 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 7 Apr 2016 21:35:26 +1000 Subject: [PATCH] Client should provide visual feedback when respawning/spawning by slightly teleporting the player up one pixel. (Thanks FrostFox) Closes #158 --- ClassicalSharp/ClassicalSharp.csproj | 1 + .../Entities/Components/InputComponent.cs | 94 +++++++++++++++++++ ClassicalSharp/Entities/LocalPlayer.cs | 69 ++------------ 3 files changed, 101 insertions(+), 63 deletions(-) create mode 100644 ClassicalSharp/Entities/Components/InputComponent.cs diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj index f931cb577..29d284bb9 100644 --- a/ClassicalSharp/ClassicalSharp.csproj +++ b/ClassicalSharp/ClassicalSharp.csproj @@ -150,6 +150,7 @@ + diff --git a/ClassicalSharp/Entities/Components/InputComponent.cs b/ClassicalSharp/Entities/Components/InputComponent.cs new file mode 100644 index 000000000..97efd7592 --- /dev/null +++ b/ClassicalSharp/Entities/Components/InputComponent.cs @@ -0,0 +1,94 @@ +// ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT +using System; +using OpenTK; +using OpenTK.Input; + +namespace ClassicalSharp.Entities { + + /// Entity component that performs input handling. + public sealed class InputComponent { + + Entity entity; + Game game; + public HacksComponent Hacks; + public CollisionsComponent collisions; + public PhysicsComponent physics; + + public InputComponent( Game game, Entity entity ) { + this.game = game; + this.entity = entity; + } + + internal bool HandleKeyDown( Key key ) { + LocalPlayer p = (LocalPlayer)entity; + KeyMap keys = game.InputHandler.Keys; + + if( key == keys[KeyBinding.Respawn] && Hacks.CanRespawn ) { + Vector3 spawn = p.SpawnPoint; + if( game.World.IsValidPos( Vector3I.Floor( spawn ) ) ) + FindHighestFree( ref spawn ); + + spawn.Y += 1/16f; + LocationUpdate update = LocationUpdate.MakePosAndOri( spawn, p.SpawnYaw, p.SpawnPitch, false ); + entity.SetLocation( update, false ); + } else if( key == keys[KeyBinding.SetSpawn] && Hacks.CanRespawn ) { + p.SpawnPoint = entity.Position; + p.SpawnYaw = entity.YawDegrees; + p.SpawnPitch = entity.PitchDegrees; + + Vector3 spawn = p.SpawnPoint; spawn.Y += 1/16f; + LocationUpdate update = LocationUpdate.MakePosAndOri( spawn, p.SpawnYaw, p.SpawnPitch, false ); + entity.SetLocation( update, false ); + } else if( key == keys[KeyBinding.Fly] && Hacks.CanFly && Hacks.Enabled ) { + Hacks.Flying = !Hacks.Flying; + } else if( key == keys[KeyBinding.NoClip] && Hacks.CanNoclip && Hacks.Enabled ) { + if( Hacks.Noclip ) entity.Velocity.Y = 0; + Hacks.Noclip = !Hacks.Noclip; + } else if( key == keys[KeyBinding.Jump] && !entity.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; + } + return true; + } + + void FindHighestFree( ref Vector3 spawn ) { + BlockInfo info = game.BlockInfo; + Vector3 size = entity.Model.CollisionSize; + BoundingBox bb = entity.CollisionBounds; + Vector3I P = Vector3I.Floor( spawn ); + int bbMax = Utils.Floor( size.Y ); + int minX = Utils.Floor( -size.X / 2 ), maxX = Utils.Floor( size.X / 2 ); + int minZ = Utils.Floor( -size.Z / 2 ), maxZ = Utils.Floor( size.Z / 2 ); + + // Spawn player at highest valid position. + for( int y = P.Y; y <= game.World.Height; y++ ) { + bool anyHit = false; + for( int yy = 0; yy <= bbMax; yy++ ) + for( int zz = minZ; zz <= maxZ; zz++ ) + for ( int xx = minX; xx <= maxX; xx++ ) + { + Vector3I coords = new Vector3I( P.X + xx, y + yy, P.Z + zz ); + byte block = collisions.GetPhysicsBlockId( coords.X, coords.Y, coords.Z ); + Vector3 min = info.MinBB[block] + (Vector3)coords; + Vector3 max = info.MaxBB[block] + (Vector3)coords; + if( !bb.Intersects( new BoundingBox( min, max ) ) ) continue; + anyHit |= info.Collide[block] == CollideType.Solid; + } + + if( !anyHit ) { + byte block = collisions.GetPhysicsBlockId( P.X, y, P.Z ); + float height = info.Collide[block] == CollideType.Solid ? info.MaxBB[block].Y : 0; + spawn.Y = y + height + Entity.Adjustment; + return; + } + } + } + } +} \ No newline at end of file diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs index f3a0ddd6d..2dae6f17f 100644 --- a/ClassicalSharp/Entities/LocalPlayer.cs +++ b/ClassicalSharp/Entities/LocalPlayer.cs @@ -28,6 +28,7 @@ namespace ClassicalSharp.Entities { internal CollisionsComponent collisions; public HacksComponent Hacks; internal PhysicsComponent physics; + internal InputComponent input; public LocalPlayer( Game game ) : base( game ) { DisplayName = game.Username; @@ -36,8 +37,10 @@ namespace ClassicalSharp.Entities { collisions = new CollisionsComponent( game, this ); Hacks = new HacksComponent( game, this ); physics = new PhysicsComponent( game, this ); - physics.hacks = Hacks; - physics.collisions = collisions; + input = new InputComponent( game, this ); + physics.hacks = Hacks; input.Hacks = Hacks; + physics.collisions = collisions; input.collisions = collisions; + input.physics = physics; Hacks.SpeedMultiplier = Options.GetFloat( OptionsKey.Speed, 0.1f, 50, 10 ); Hacks.PushbackPlacing = !game.ClassicMode && Options.GetBool( OptionsKey.PushbackPlacing, false ); @@ -229,66 +232,6 @@ namespace ClassicalSharp.Entities { count--; } - internal bool HandleKeyDown( Key key ) { - KeyMap keys = game.InputHandler.Keys; - if( key == keys[KeyBinding.Respawn] && Hacks.CanRespawn ) { - Vector3 spawn = SpawnPoint; - if( game.World.IsValidPos( Vector3I.Floor( spawn ) ) ) - FindHighestFree( ref spawn ); - LocationUpdate update = LocationUpdate.MakePosAndOri( spawn, SpawnYaw, SpawnPitch, false ); - SetLocation( update, false ); - } else if( key == keys[KeyBinding.SetSpawn] && Hacks.CanRespawn ) { - SpawnPoint = Position; - SpawnYaw = HeadYawDegrees; - SpawnPitch = PitchDegrees; - } else if( key == keys[KeyBinding.Fly] && Hacks.CanFly && Hacks.Enabled ) { - Hacks.Flying = !Hacks.Flying; - } else if( key == keys[KeyBinding.NoClip] && Hacks.CanNoclip && Hacks.Enabled ) { - 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; - } - return true; - } - - void FindHighestFree( ref Vector3 spawn ) { - Vector3 size = Model.CollisionSize; - BoundingBox bb = CollisionBounds; - Vector3I P = Vector3I.Floor( spawn ); - int bbMax = Utils.Floor( size.Y ); - int minX = Utils.Floor( -size.X / 2 ), maxX = Utils.Floor( size.X / 2 ); - int minZ = Utils.Floor( -size.Z / 2 ), maxZ = Utils.Floor( size.Z / 2 ); - - // Spawn player at highest valid position. - for( int y = P.Y; y <= game.World.Height; y++ ) { - bool anyHit = false; - for( int yy = 0; yy <= bbMax; yy++ ) - for( int zz = minZ; zz <= maxZ; zz++ ) - for ( int xx = minX; xx <= maxX; xx++ ) - { - Vector3I coords = new Vector3I( P.X + xx, y + yy, P.Z + zz ); - byte block = collisions.GetPhysicsBlockId( coords.X, coords.Y, coords.Z ); - Vector3 min = info.MinBB[block] + (Vector3)coords; - Vector3 max = info.MaxBB[block] + (Vector3)coords; - if( !bb.Intersects( new BoundingBox( min, max ) ) ) continue; - anyHit |= info.Collide[block] == CollideType.Solid; - } - - if( !anyHit ) { - byte block = collisions.GetPhysicsBlockId( P.X, y, P.Z ); - spawn.Y = y + info.MaxBB[block].Y + Entity.Adjustment; - return; - } - } - } + internal bool HandleKeyDown( Key key ) { return input.HandleKeyDown( key ); } } } \ No newline at end of file