diff --git a/ClassicalSharp/ClassicalSharp.csproj b/ClassicalSharp/ClassicalSharp.csproj
index ea19983c9..b841d29ae 100644
--- a/ClassicalSharp/ClassicalSharp.csproj
+++ b/ClassicalSharp/ClassicalSharp.csproj
@@ -150,13 +150,14 @@
-
-
-
+
+
+
+
-
+
@@ -167,6 +168,7 @@
+
@@ -341,8 +343,9 @@
-
+
+
diff --git a/ClassicalSharp/Entities/Components/LocalInterpComponent.cs b/ClassicalSharp/Entities/Components/LocalInterpComponent.cs
new file mode 100644
index 000000000..e3e3563ee
--- /dev/null
+++ b/ClassicalSharp/Entities/Components/LocalInterpComponent.cs
@@ -0,0 +1,71 @@
+// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
+using System;
+using ClassicalSharp.Renderers;
+using OpenTK;
+
+namespace ClassicalSharp.Entities {
+
+ /// Entity component that performs interpolation of position and model head yaw over time.
+ public sealed class LocalInterpComponent {
+
+ Entity entity;
+ public LocalInterpComponent(Game game, Entity entity) {
+ this.entity = entity;
+ }
+
+ internal Vector3 lastPos, nextPos;
+ internal float lastHeadYaw, nextHeadYaw, lastPitch, nextPitch, lastYaw, nextYaw;
+ int yawStateCount;
+ float[] yawStates = new float[15];
+
+ public void SetLocation(LocationUpdate update, bool interpolate) {
+ if (update.IncludesPosition) {
+ nextPos = update.RelativePosition ? nextPos + update.Pos : update.Pos;
+ double blockOffset = nextPos.Y - Math.Floor(nextPos.Y);
+ if (blockOffset < Entity.Adjustment)
+ nextPos.Y += Entity.Adjustment;
+ if (!interpolate) {
+ lastPos = entity.Position = nextPos;
+ }
+ }
+
+ if (update.IncludesOrientation) {
+ nextHeadYaw = update.Yaw;
+ nextPitch = update.Pitch;
+ if (!interpolate) {
+ lastHeadYaw = entity.YawDegrees = nextHeadYaw;
+ lastPitch = entity.PitchDegrees = nextPitch;
+ entity.HeadYawDegrees = entity.YawDegrees;
+ yawStateCount = 0;
+ } else {
+ for (int i = 0; i < 3; i++)
+ AddYaw(Utils.LerpAngle(lastHeadYaw, nextHeadYaw, (i + 1) / 3f));
+ }
+ }
+ }
+
+ public void AdvanceState() {
+ lastPos = entity.Position = nextPos;
+ lastHeadYaw = nextHeadYaw;
+ lastYaw = nextYaw;
+ lastPitch = nextPitch;
+
+ if (yawStateCount > 0) {
+ nextYaw = yawStates[0];
+ RemoveOldest(yawStates, ref yawStateCount);
+ }
+ }
+
+ void AddYaw(float state) {
+ if (yawStateCount == yawStates.Length)
+ RemoveOldest(yawStates, ref yawStateCount);
+ yawStates[yawStateCount++] = state;
+ }
+
+ void RemoveOldest(T[] array, ref int count) {
+ for (int i = 0; i < array.Length - 1; i++)
+ array[i] = array[i + 1];
+ count--;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ClassicalSharp/Entities/Components/InterpolatedComponent.cs b/ClassicalSharp/Entities/Components/NetInterpComponent.cs
similarity index 96%
rename from ClassicalSharp/Entities/Components/InterpolatedComponent.cs
rename to ClassicalSharp/Entities/Components/NetInterpComponent.cs
index a1c04da47..b618b4008 100644
--- a/ClassicalSharp/Entities/Components/InterpolatedComponent.cs
+++ b/ClassicalSharp/Entities/Components/NetInterpComponent.cs
@@ -6,10 +6,10 @@ using OpenTK;
namespace ClassicalSharp.Entities {
/// Entity component that performs interpolation of position and model head yaw over time.
- public sealed class InterpolatedComponent {
+ public sealed class NetInterpComponent {
Entity entity;
- public InterpolatedComponent(Game game, Entity entity) {
+ public NetInterpComponent(Game game, Entity entity) {
this.entity = entity;
}
diff --git a/ClassicalSharp/Entities/Components/SoundComponent.cs b/ClassicalSharp/Entities/Components/SoundComponent.cs
index 6e722b6ae..5df8d7c12 100644
--- a/ClassicalSharp/Entities/Components/SoundComponent.cs
+++ b/ClassicalSharp/Entities/Components/SoundComponent.cs
@@ -22,7 +22,7 @@ namespace ClassicalSharp.Entities {
Vector3 lastSoundPos;
public void Tick(bool wasOnGround) {
- Vector3 soundPos = p.nextPos;
+ Vector3 soundPos = p.interp.nextPos;
GetSound();
if (!anyNonAir) soundPos = Utils.MaxPos();
@@ -55,7 +55,7 @@ namespace ClassicalSharp.Entities {
bool anyNonAir = false;
SoundType sndType = SoundType.None;
void GetSound() {
- Vector3 pos = p.nextPos;
+ Vector3 pos = p.interp.nextPos;
AABB bounds = p.Bounds;
sndType = SoundType.None;
anyNonAir = false;
diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs
index ffc659a6f..29610691f 100644
--- a/ClassicalSharp/Entities/LocalPlayer.cs
+++ b/ClassicalSharp/Entities/LocalPlayer.cs
@@ -26,12 +26,13 @@ namespace ClassicalSharp.Entities {
get { return (float)PhysicsComponent.GetMaxHeight(physics.jumpVel); }
}
- internal float curWalkTime, curSwing;
+ internal float curSwing;
internal CollisionsComponent collisions;
public HacksComponent Hacks;
internal PhysicsComponent physics;
internal InputComponent input;
internal SoundComponent sound;
+ internal LocalInterpComponent interp;
public LocalPlayer(Game game) : base(game) {
DisplayName = game.Username;
@@ -43,6 +44,7 @@ namespace ClassicalSharp.Entities {
physics = new PhysicsComponent(game, this);
input = new InputComponent(game, this);
sound = new SoundComponent(game, this);
+ interp = new LocalInterpComponent(game, this);
physics.hacks = Hacks; input.Hacks = Hacks;
physics.collisions = collisions;
@@ -55,9 +57,7 @@ namespace ClassicalSharp.Entities {
&& Hacks.CanSpeed ? 1 : 0.5f;
OldVelocity = Velocity;
float xMoving = 0, zMoving = 0;
- lastPos = Position = nextPos;
- lastYaw = nextYaw;
- lastPitch = nextPitch;
+ interp.AdvanceState();
bool wasOnGround = onGround;
HandleInput(ref xMoving, ref zMoving);
@@ -65,20 +65,17 @@ namespace ClassicalSharp.Entities {
physics.UpdateVelocityState(xMoving, zMoving);
physics.PhysicsTick(xMoving, zMoving);
- nextPos = Position;
- Position = lastPos;
- anim.UpdateAnimState(lastPos, nextPos, delta);
+ interp.nextPos = Position; Position = interp.lastPos;
+ anim.UpdateAnimState(interp.lastPos, interp.nextPos, delta);
CheckSkin();
sound.Tick(wasOnGround);
- UpdateCurrentBodyYaw();
}
public override void RenderModel(double deltaTime, float t) {
anim.GetCurrentAnimState(t);
curSwing = Utils.Lerp(anim.swingO, anim.swingN, t);
- curWalkTime = Utils.Lerp(anim.walkTimeO, anim.walkTimeN, t);
-
+
if (!game.Camera.IsThirdPerson) return;
Model.Render(this);
}
@@ -118,65 +115,18 @@ namespace ClassicalSharp.Entities {
}
}
- internal Vector3 lastPos, nextPos;
- internal float lastYaw, nextYaw, lastPitch, nextPitch;
- float newYaw, oldYaw;
- int yawStateCount;
- float[] yawStates = new float[15];
-
public override void SetLocation(LocationUpdate update, bool interpolate) {
- if (update.IncludesPosition) {
- nextPos = update.RelativePosition ? nextPos + update.Pos : update.Pos;
- double blockOffset = nextPos.Y - Math.Floor(nextPos.Y);
- if (blockOffset < Entity.Adjustment)
- nextPos.Y += Entity.Adjustment;
- if (!interpolate) {
- lastPos = Position = nextPos;
- }
- }
- if (update.IncludesOrientation) {
- nextYaw = update.Yaw;
- nextPitch = update.Pitch;
- if (!interpolate) {
- lastYaw = YawDegrees = nextYaw;
- lastPitch = PitchDegrees = nextPitch;
- HeadYawDegrees = YawDegrees;
- yawStateCount = 0;
- } else {
- for (int i = 0; i < 3; i++)
- AddYaw(Utils.LerpAngle(lastYaw, nextYaw, (i + 1) / 3f));
- }
- }
+ interp.SetLocation(update, interpolate);
}
/// Linearly interpolates position and rotation between the previous and next state.
public void SetInterpPosition(float t) {
if (!Hacks.WOMStyleHacks || !Hacks.Noclip)
- Position = Vector3.Lerp(lastPos, nextPos, t);
+ Position = Vector3.Lerp(interp.lastPos, interp.nextPos, t);
- HeadYawDegrees = Utils.LerpAngle(lastYaw, nextYaw, t);
- YawDegrees = Utils.LerpAngle(oldYaw, newYaw, t);
- PitchDegrees = Utils.LerpAngle(lastPitch, nextPitch, t);
- }
-
- void AddYaw(float state) {
- if (yawStateCount == yawStates.Length)
- RemoveOldest(yawStates, ref yawStateCount);
- yawStates[yawStateCount++] = state;
- }
-
- void UpdateCurrentBodyYaw() {
- oldYaw = newYaw;
- if (yawStateCount > 0) {
- newYaw = yawStates[0];
- RemoveOldest(yawStates, ref yawStateCount);
- }
- }
-
- void RemoveOldest(T[] array, ref int count) {
- for (int i = 0; i < array.Length - 1; i++)
- array[i] = array[i + 1];
- count--;
+ HeadYawDegrees = Utils.LerpAngle(interp.lastHeadYaw, interp.nextHeadYaw, t);
+ YawDegrees = Utils.LerpAngle(interp.lastYaw, interp.nextYaw, t);
+ PitchDegrees = Utils.LerpAngle(interp.lastPitch, interp.nextPitch, t);
}
public void Init(Game game) {
diff --git a/ClassicalSharp/Entities/AI/AI.cs b/ClassicalSharp/Entities/Mobs/AI/AI.cs
similarity index 96%
rename from ClassicalSharp/Entities/AI/AI.cs
rename to ClassicalSharp/Entities/Mobs/AI/AI.cs
index 99ffb8de6..7f063aaf6 100644
--- a/ClassicalSharp/Entities/AI/AI.cs
+++ b/ClassicalSharp/Entities/Mobs/AI/AI.cs
@@ -2,7 +2,7 @@
using System;
using OpenTK;
-namespace ClassicalSharp.Entities {
+namespace ClassicalSharp.Entities.Mobs {
public abstract class AI {
diff --git a/ClassicalSharp/Entities/AI/FleeAI.cs b/ClassicalSharp/Entities/Mobs/AI/FleeAI.cs
similarity index 91%
rename from ClassicalSharp/Entities/AI/FleeAI.cs
rename to ClassicalSharp/Entities/Mobs/AI/FleeAI.cs
index a292f69f1..455bf2c7d 100644
--- a/ClassicalSharp/Entities/AI/FleeAI.cs
+++ b/ClassicalSharp/Entities/Mobs/AI/FleeAI.cs
@@ -2,7 +2,7 @@
using System;
using OpenTK;
-namespace ClassicalSharp.Entities {
+namespace ClassicalSharp.Entities.Mobs {
public sealed class FleeAI : AI {
diff --git a/ClassicalSharp/Entities/AI/HostileAI.cs b/ClassicalSharp/Entities/Mobs/AI/HostileAI.cs
similarity index 93%
rename from ClassicalSharp/Entities/AI/HostileAI.cs
rename to ClassicalSharp/Entities/Mobs/AI/HostileAI.cs
index ba6cc2bed..fa38119f0 100644
--- a/ClassicalSharp/Entities/AI/HostileAI.cs
+++ b/ClassicalSharp/Entities/Mobs/AI/HostileAI.cs
@@ -2,7 +2,7 @@
using System;
using OpenTK;
-namespace ClassicalSharp.Entities {
+namespace ClassicalSharp.Entities.Mobs {
public sealed class HostileAI : AI {
diff --git a/ClassicalSharp/Entities/Mobs/MobEntity.cs b/ClassicalSharp/Entities/Mobs/MobEntity.cs
new file mode 100644
index 000000000..caed43251
--- /dev/null
+++ b/ClassicalSharp/Entities/Mobs/MobEntity.cs
@@ -0,0 +1,42 @@
+// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
+using System;
+using OpenTK;
+
+namespace ClassicalSharp.Entities.Mobs {
+
+ public class MobEntity : Entity {
+
+ LocalInterpComponent interp;
+ public MobEntity(Game game, string model) : base(game) {
+ StepSize = 0.5f;
+ SetModel(model);
+ interp = new LocalInterpComponent(game, this);
+ }
+
+ public override void Despawn() { }
+ public override void RenderName() { }
+
+ // TODO: this is just so the entities do something, remove later
+ static Random rand = new Random();
+ public override void Tick(double delta) {
+ interp.AdvanceState();
+ float inc = rand.Next(0, 10);
+ LocationUpdate update = LocationUpdate.MakeOri(interp.nextHeadYaw + inc, 0);
+ SetLocation(update, true);
+ }
+
+ public override void SetLocation(LocationUpdate update, bool interpolate) {
+ interp.SetLocation(update, interpolate);
+ }
+
+ public override void RenderModel(double deltaTime, float t) {
+ Position = Vector3.Lerp(interp.lastPos, interp.nextPos, t);
+ HeadYawDegrees = Utils.LerpAngle(interp.lastHeadYaw, interp.nextHeadYaw, t);
+ YawDegrees = Utils.LerpAngle(interp.lastYaw, interp.nextYaw, t);
+ PitchDegrees = Utils.LerpAngle(interp.lastPitch, interp.nextPitch, t);
+
+ anim.GetCurrentAnimState(t);
+ Model.Render(this);
+ }
+ }
+}
diff --git a/ClassicalSharp/Entities/NetPlayer.cs b/ClassicalSharp/Entities/NetPlayer.cs
index 581c286e0..e7e4f7aff 100644
--- a/ClassicalSharp/Entities/NetPlayer.cs
+++ b/ClassicalSharp/Entities/NetPlayer.cs
@@ -6,12 +6,12 @@ namespace ClassicalSharp.Entities {
public sealed class NetPlayer : Player {
- InterpolatedComponent interp;
+ NetInterpComponent interp;
public NetPlayer(string displayName, string skinName, Game game, byte id) : base(game) {
DisplayName = displayName;
SkinName = skinName;
SkinIdentifier = "skin_" + id;
- interp = new InterpolatedComponent(game, this);
+ interp = new NetInterpComponent(game, this);
}
public override void SetLocation(LocationUpdate update, bool interpolate) {
diff --git a/ClassicalSharp/Game/PickingHandler.cs b/ClassicalSharp/Game/PickingHandler.cs
index 2545643b2..296c0fccf 100644
--- a/ClassicalSharp/Game/PickingHandler.cs
+++ b/ClassicalSharp/Game/PickingHandler.cs
@@ -84,7 +84,7 @@ namespace ClassicalSharp {
// NOTE: We need to also test against nextPos here, because otherwise
// we can fall through the block as collision is performed against nextPos
AABB localBB = AABB.Make(p.Position, p.Size);
- localBB.Min.Y = Math.Min(p.nextPos.Y, localBB.Min.Y);
+ localBB.Min.Y = Math.Min(p.interp.nextPos.Y, localBB.Min.Y);
if (p.Hacks.Noclip || !localBB.Intersects(blockBB)) return true;
if (p.Hacks.CanPushbackBlocks && p.Hacks.PushbackPlacing && p.Hacks.Enabled)
@@ -94,7 +94,7 @@ namespace ClassicalSharp {
if (localBB.Intersects(blockBB)) return false;
// Push player up if they are jumping and trying to place a block underneath them.
- Vector3 next = game.LocalPlayer.nextPos;
+ Vector3 next = game.LocalPlayer.interp.nextPos;
next.Y = pos.Y + game.BlockInfo.MaxBB[block].Y + Entity.Adjustment;
LocationUpdate update = LocationUpdate.MakePos(next, false);
game.LocalPlayer.SetLocation(update, false);
diff --git a/ClassicalSharp/Mode/Survival.cs b/ClassicalSharp/Mode/Survival.cs
index 74922841c..530662ae0 100644
--- a/ClassicalSharp/Mode/Survival.cs
+++ b/ClassicalSharp/Mode/Survival.cs
@@ -1,5 +1,8 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
+using ClassicalSharp.Entities;
+using ClassicalSharp.Entities.Mobs;
+using OpenTK;
using OpenTK.Input;
namespace ClassicalSharp.Mode {
@@ -40,7 +43,8 @@ namespace ClassicalSharp.Mode {
}
public bool PickEntity(byte id) {
- return false;
+ game.Chat.Add("PICKED ON: " + id + "," + game.Entities[id].ModelName);
+ return true;
}
@@ -92,6 +96,17 @@ namespace ClassicalSharp.Mode {
public void OnNewMapLoaded(Game game) {
game.Chat.Add("&fScore: &e" + score, MessageType.Status1);
+
+ string[] models = { "sheep", "pig", "skeleton", "zombie", "creeper" };
+ for (int i = 0; i < 254; i++) {
+ MobEntity fail = new MobEntity(game, models[rnd.Next(models.Length)]);
+ float x = rnd.Next(0, game.World.Width) + 0.5f;
+ float z = rnd.Next(0, game.World.Length) + 0.5f;
+
+ Vector3 pos = Respawn.FindSpawnPosition(game, x, z, fail.Size);
+ fail.SetLocation(LocationUpdate.MakePos(pos, false), false);
+ game.Entities[i] = fail;
+ }
}
public void Init(Game game) {
diff --git a/ClassicalSharp/Singleplayer/Server.cs b/ClassicalSharp/Singleplayer/Server.cs
index 0eda0e645..ba5908931 100644
--- a/ClassicalSharp/Singleplayer/Server.cs
+++ b/ClassicalSharp/Singleplayer/Server.cs
@@ -110,24 +110,12 @@ namespace ClassicalSharp.Singleplayer {
this.generator = generator;
game.Gui.SetNewScreen(new LoadingMapScreen(game, "Generating level", "Generating.."));
generator.GenerateAsync(game, width, height, length, seed);
- }
-
+ }
void ResetPlayerPosition() {
- Vector3 spawn = default(Vector3);
- spawn.X = (game.World.Width / 2) + 0.5f;
- spawn.Y = game.World.Height + Entity.Adjustment;
- spawn.Z = (game.World.Length / 2) + 0.5f;
-
- AABB bb = AABB.Make(spawn, game.LocalPlayer.Size);
- spawn.Y = 0;
- for (int y = game.World.Height; y >= 0; y--) {
- float highestY = Respawn.HighestFreeY(game, ref bb);
- if (highestY != float.NegativeInfinity) {
- spawn.Y = highestY; break;
- }
- bb.Min.Y -= 1; bb.Max.Y -= 1;
- }
+ float x = (game.World.Width / 2) + 0.5f;
+ float z = (game.World.Length / 2) + 0.5f;
+ Vector3 spawn = Respawn.FindSpawnPosition(game, x, z, game.LocalPlayer.Size);
LocationUpdate update = LocationUpdate.MakePosAndOri(spawn, 0, 0, false);
game.LocalPlayer.SetLocation(update, false);
diff --git a/ClassicalSharp/Utils/Camera.cs b/ClassicalSharp/Utils/Camera.cs
index 875207dec..2f52088af 100644
--- a/ClassicalSharp/Utils/Camera.cs
+++ b/ClassicalSharp/Utils/Camera.cs
@@ -94,14 +94,14 @@ namespace ClassicalSharp {
static readonly float sensiFactor = 0.0002f / 3 * Utils.Rad2Deg;
private void UpdateMouseRotation() {
float sensitivity = sensiFactor * game.MouseSensitivity;
- float yaw = player.nextYaw + delta.X * sensitivity;
+ float yaw = player.interp.nextHeadYaw + delta.X * sensitivity;
float yAdj = game.InvertMouse ? -delta.Y * sensitivity : delta.Y * sensitivity;
- float pitch = player.nextPitch + yAdj;
+ float pitch = player.interp.nextPitch + yAdj;
LocationUpdate update = LocationUpdate.MakeOri(yaw, pitch);
// Need to make sure we don't cross the vertical axes, because that gets weird.
if (update.Pitch >= 90 && update.Pitch <= 270)
- update.Pitch = player.nextPitch < 180 ? 89.9f : 270.1f;
+ update.Pitch = player.interp.nextPitch < 180 ? 89.9f : 270.1f;
game.LocalPlayer.SetLocation(update, true);
}
diff --git a/ClassicalSharp/Utils/Respawn.cs b/ClassicalSharp/Utils/Respawn.cs
index 1c3c1a362..4c2cd718d 100644
--- a/ClassicalSharp/Utils/Respawn.cs
+++ b/ClassicalSharp/Utils/Respawn.cs
@@ -1,5 +1,6 @@
// Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3
using System;
+using ClassicalSharp.Entities;
using ClassicalSharp.Physics;
using OpenTK;
@@ -31,5 +32,21 @@ namespace ClassicalSharp {
}
return spawnY;
}
+
+ public static Vector3 FindSpawnPosition(Game game, float x, float z, Vector3 modelSize) {
+ Vector3 spawn = new Vector3(x, 0, z);
+ spawn.Y = game.World.Height + Entity.Adjustment;
+ AABB bb = AABB.Make(spawn, modelSize);
+ spawn.Y = 0;
+
+ for (int y = game.World.Height; y >= 0; y--) {
+ float highestY = HighestFreeY(game, ref bb);
+ if (highestY != float.NegativeInfinity) {
+ spawn.Y = highestY; break;
+ }
+ bb.Min.Y -= 1; bb.Max.Y -= 1;
+ }
+ return spawn;
+ }
}
}
\ No newline at end of file