diff --git a/TrueCraft.Client.Linux/Handlers/PacketHandlers.cs b/TrueCraft.Client.Linux/Handlers/PacketHandlers.cs index 2a4f89a..2f31f32 100644 --- a/TrueCraft.Client.Linux/Handlers/PacketHandlers.cs +++ b/TrueCraft.Client.Linux/Handlers/PacketHandlers.cs @@ -3,6 +3,7 @@ using TrueCraft.API.Networking; using TrueCraft.Core.Networking.Packets; using TrueCraft.Core.Networking; using TrueCraft.Client.Linux.Events; +using TrueCraft.API; namespace TrueCraft.Client.Linux.Handlers { @@ -12,6 +13,7 @@ namespace TrueCraft.Client.Linux.Handlers { client.RegisterPacketHandler(new HandshakeResponsePacket().ID, HandleHandshake); client.RegisterPacketHandler(new ChatMessagePacket().ID, HandleChatMessage); + client.RegisterPacketHandler(new SetPlayerPositionPacket().ID, HandlePositionAndLook); client.RegisterPacketHandler(new ChunkPreamblePacket().ID, ChunkHandler.HandleChunkPreamble); client.RegisterPacketHandler(new ChunkDataPacket().ID, ChunkHandler.HandleChunkData); @@ -29,5 +31,12 @@ namespace TrueCraft.Client.Linux.Handlers Console.WriteLine("Got handshake with {0}", packet.ConnectionHash); // TODO: Authenticate? client.QueuePacket(new LoginRequestPacket(PacketReader.Version, "TestUser")); } + + public static void HandlePositionAndLook(IPacket _packet, MultiplayerClient client) + { + var packet = (SetPlayerPositionPacket)_packet; + client._Position = new Vector3(packet.X, packet.Y, packet.Z); + // TODO: Pitch and yaw + } } } \ No newline at end of file diff --git a/TrueCraft.Client.Linux/MultiplayerClient.cs b/TrueCraft.Client.Linux/MultiplayerClient.cs index 51f4869..ffe15e6 100644 --- a/TrueCraft.Client.Linux/MultiplayerClient.cs +++ b/TrueCraft.Client.Linux/MultiplayerClient.cs @@ -7,22 +7,23 @@ using System.Threading; using TrueCraft.Core.Networking; using System.Linq; using TrueCraft.Core.Networking.Packets; - -// TODO: Make IMultiplayerClient and so on using TrueCraft.Client.Linux.Events; - +using TrueCraft.Core.Logic; +using TrueCraft.API.Entities; +using TrueCraft.API; namespace TrueCraft.Client.Linux { public delegate void PacketHandler(IPacket packet, MultiplayerClient client); - public class MultiplayerClient + public class MultiplayerClient : IAABBEntity // TODO: Make IMultiplayerClient and so on { public event EventHandler ChatMessage; public event EventHandler ChunkLoaded; public event EventHandler ChunkUnloaded; public ReadOnlyWorld World { get; private set; } + public PhysicsEngine Physics { get; set; } private TcpClient Client { get; set; } private IMinecraftStream Stream { get; set; } @@ -41,6 +42,10 @@ namespace TrueCraft.Client.Linux PacketHandlers = new PacketHandler[0x100]; Handlers.PacketHandlers.RegisterHandlers(this); World = new ReadOnlyWorld(); + var repo = new BlockRepository(); + repo.DiscoverBlockProviders(); + World.World.BlockRepository = repo; + Physics = new PhysicsEngine(World, repo); } public void RegisterPacketHandler(byte packetId, PacketHandler handler) @@ -53,6 +58,14 @@ namespace TrueCraft.Client.Linux Client.BeginConnect(endPoint.Address, endPoint.Port, ConnectionComplete, null); } + public void Disconnect() + { + NetworkWorker.Abort(); + new DisconnectPacket("Disconnecting").WritePacket(Stream); + Stream.BaseStream.Flush(); + Client.Close(); + } + public void QueuePacket(IPacket packet) { PacketQueue.Enqueue(packet); @@ -63,6 +76,7 @@ namespace TrueCraft.Client.Linux Client.EndConnect(result); Stream = new MinecraftStream(new BufferedStream(Client.GetStream())); NetworkWorker.Start(); + Physics.AddEntity(this); QueuePacket(new HandshakePacket("TestUser")); // TODO: Get username from somewhere else } @@ -107,5 +121,86 @@ namespace TrueCraft.Client.Linux { if (ChunkUnloaded != null) ChunkUnloaded(this, e); } + + #region IAABBEntity implementation + + public const double Width = 0.6; + public const double Height = 1.62; + public const double Depth = 0.6; + + public void TerrainCollision(Vector3 collisionPoint, Vector3 collisionDirection) + { + // This space intentionally left blank + } + + public BoundingBox BoundingBox + { + get + { + return new BoundingBox(Position, Position + Size); + } + } + + public Size Size + { + get { return new Size(Width, Height, Depth); } + } + + #endregion + + #region IPhysicsEntity implementation + + public bool BeginUpdate() + { + return true; + } + + public void EndUpdate(Vector3 newPosition) + { + Position = newPosition; + } + + internal Vector3 _Position; + public Vector3 Position + { + get + { + return _Position; + } + set + { + if (_Position != value) + QueuePacket(new PlayerPositionAndLookPacket(value.X, value.Y, value.Y + Height, value.Z, 0, 0, false)); + _Position = value; + } + } + + public Vector3 Velocity { get; set; } + + public float AccelerationDueToGravity + { + get + { + return 0.08f; + } + } + + public float Drag + { + get + { + return 0.02f; + } + } + + public float TerminalVelocity + { + get + { + return 3.92f; + } + } + + #endregion } } \ No newline at end of file diff --git a/TrueCraft.Client.Linux/PhysicsEngine.cs b/TrueCraft.Client.Linux/PhysicsEngine.cs new file mode 100644 index 0000000..ac3b210 --- /dev/null +++ b/TrueCraft.Client.Linux/PhysicsEngine.cs @@ -0,0 +1,405 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using TrueCraft.Core.World; +using TrueCraft.API.Entities; +using TrueCraft.API.World; +using TrueCraft.API; +using TrueCraft.Client.Linux; + +namespace TrueCraft +{ + // This is a stripped down version of the physics engine that the server uses + // The only thing we use it for is our own movement + public class PhysicsEngine + { + public PhysicsEngine(ReadOnlyWorld world, IBlockPhysicsProvider physicsProvider) + { + World = world; + Entities = new List(); + EntityLock = new object(); + LastUpdate = DateTime.MinValue; + BlockPhysicsProvider = physicsProvider; + MillisecondsBetweenUpdates = 1000 / 20; + } + + public int MillisecondsBetweenUpdates { get; set; } + public ReadOnlyWorld World { get; set; } + public IBlockPhysicsProvider BlockPhysicsProvider { get; set; } + public List Entities { get; set; } + private object EntityLock { get; set; } + private DateTime LastUpdate { get; set; } + + public void AddEntity(IPhysicsEntity entity) + { + if (Entities.Contains(entity)) + return; + lock (EntityLock) + Entities.Add(entity); + } + + public void RemoveEntity(IPhysicsEntity entity) + { + if (!Entities.Contains(entity)) + return; + lock (EntityLock) + Entities.Remove(entity); + } + + private BoundingBox TempBoundingBox; + public void Update() + { + double multipler = (DateTime.Now - LastUpdate).TotalMilliseconds / MillisecondsBetweenUpdates; + if (LastUpdate == DateTime.MinValue) + multipler = 1; + if (multipler > 5) multipler = 5; + if (multipler < 0.1) multipler = 0.1; + lock (EntityLock) + { + for (int i = 0; i < Entities.Count; i++) + { + var entity = Entities[i]; + if (entity.BeginUpdate()) + { + entity.Velocity -= new Vector3(0, entity.AccelerationDueToGravity * multipler, 0); + entity.Velocity.Clamp(entity.TerminalVelocity); + if (entity is IAABBEntity) + CheckWithTerrain((IAABBEntity)entity, World); + entity.EndUpdate(entity.Position + entity.Velocity); + } + } + } + LastUpdate = DateTime.Now; + } + + private void CheckWithTerrain(IAABBEntity entity, ReadOnlyWorld world) + { + Vector3 collisionPoint, collisionDirection; + if (entity.Position.Y > 0 && entity.Position.Y <= 127) // Don't do checks outside the map + { + bool fireEvent = entity.Velocity != Vector3.Zero; + // Do terrain collisions + if (AdjustVelocityX(entity, world, out collisionPoint, out collisionDirection)) + { + if (fireEvent) + entity.TerrainCollision(collisionPoint, collisionDirection); + } + if (AdjustVelocityY(entity, world, out collisionPoint, out collisionDirection)) + { + entity.Velocity *= new Vector3(0.1, 1, 0.1); // TODO: More sophisticated friction + if (fireEvent) + entity.TerrainCollision(collisionPoint, collisionDirection); + } + if (AdjustVelocityZ(entity, world, out collisionPoint, out collisionDirection)) + { + if (fireEvent) + entity.TerrainCollision(collisionPoint, collisionDirection); + } + } + } + + // TODO: There's a lot of code replication here, perhaps it can be consolidated + /// + /// Performs terrain collision tests and adjusts the X-axis velocity accordingly + /// + /// True if the entity collides with the terrain + private bool AdjustVelocityX(IAABBEntity entity, ReadOnlyWorld world, out Vector3 collision, out Vector3 collisionDirection) + { + collision = Vector3.Zero; + collisionDirection = Vector3.Zero; + if (entity.Velocity.X == 0) + return false; + // Do some enviornment guessing to improve speed + int minY = (int)entity.Position.Y - (entity.Position.Y < 0 ? 1 : 0); + int maxY = (int)(entity.Position.Y + entity.Size.Width) - (entity.Position.Y < 0 ? 1 : 0); + int minZ = (int)entity.Position.Z - (entity.Position.Z < 0 ? 1 : 0); + int maxZ = (int)(entity.Position.Z + entity.Size.Depth) - (entity.Position.Z < 0 ? 1 : 0); + int minX, maxX; + + // Expand bounding box to include area to be tested + if (entity.Velocity.X < 0) + { + TempBoundingBox = new BoundingBox( + new Vector3(entity.BoundingBox.Min.X + entity.Velocity.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z), + entity.BoundingBox.Max); + + maxX = (int)(TempBoundingBox.Max.X); + minX = (int)(TempBoundingBox.Min.X + entity.Velocity.X) - 1; + } + else + { + TempBoundingBox = new BoundingBox( + entity.BoundingBox.Min, + new Vector3(entity.BoundingBox.Max.X + entity.Velocity.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z)); + minX = (int)(entity.BoundingBox.Min.X); + maxX = (int)(entity.BoundingBox.Max.X + entity.Velocity.X) + 1; + } + + // Do terrain checks + double? collisionPoint = null; + BoundingBox blockBox; + for (int x = minX; x <= maxX; x++) + { + for (int y = minY; y <= maxY; y++) + { + for (int z = minZ; z <= maxZ; z++) + { + var position = new Coordinates3D(x, y, z); + var boundingBox = BlockPhysicsProvider.GetBoundingBox(world.World, position); + if (boundingBox == null) + continue; + blockBox = boundingBox.Value.OffsetBy(position + new Vector3(0.5)); + if (TempBoundingBox.Intersects(blockBox)) + { + if (entity.Velocity.X < 0) + { + if (!collisionPoint.HasValue) + collisionPoint = blockBox.Max.X; + else if (collisionPoint.Value < blockBox.Max.X) + collisionPoint = blockBox.Max.X; + } + else + { + if (!collisionPoint.HasValue) + collisionPoint = blockBox.Min.X; + else if (collisionPoint.Value > blockBox.Min.X) + collisionPoint = blockBox.Min.X; + } + collision = position; + } + } + } + } + + if (collisionPoint != null) + { + if (entity.Velocity.X < 0) + { + entity.Velocity = new Vector3( + entity.Velocity.X - (TempBoundingBox.Min.X - collisionPoint.Value), + entity.Velocity.Y, + entity.Velocity.Z); + collisionDirection = Vector3.Left; + } + else if (entity.Velocity.X > 0) + { + entity.Velocity = new Vector3( + entity.Velocity.X - (TempBoundingBox.Max.X - collisionPoint.Value), + entity.Velocity.Y, + entity.Velocity.Z); + collisionDirection = Vector3.Right; + } + return true; + } + + return false; + } + + /// + /// Performs terrain collision tests and adjusts the Y-axis velocity accordingly + /// + /// True if the entity collides with the terrain + private bool AdjustVelocityY(IAABBEntity entity, ReadOnlyWorld world, out Vector3 collision, out Vector3 collisionDirection) + { + collision = Vector3.Zero; + collisionDirection = Vector3.Zero; + if (entity.Velocity.Y == 0) + return false; + // Do some enviornment guessing to improve speed + int minX = (int)entity.Position.X - (entity.Position.X < 0 ? 1 : 0); + int maxX = (int)(entity.Position.X + entity.Size.Width) - (entity.Position.X < 0 ? 1 : 0); + int minZ = (int)entity.Position.Z - (entity.Position.Z < 0 ? 1 : 0); + int maxZ = (int)(entity.Position.Z + entity.Size.Depth) - (entity.Position.Z < 0 ? 1 : 0); + int minY, maxY; + + // Expand bounding box to include area to be tested + if (entity.Velocity.Y < 0) + { + TempBoundingBox = new BoundingBox( + new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y + entity.Velocity.Y, entity.BoundingBox.Min.Z), + entity.BoundingBox.Max); + + maxY = (int)(TempBoundingBox.Max.Y); + minY = (int)(TempBoundingBox.Min.Y + entity.Velocity.Y) - 1; + } + else + { + TempBoundingBox = new BoundingBox( + entity.BoundingBox.Min, + new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y + entity.Velocity.Y, entity.BoundingBox.Max.Z)); + minY = (int)(entity.BoundingBox.Min.Y); + maxY = (int)(entity.BoundingBox.Max.Y + entity.Velocity.Y) + 1; + } + + // Clamp Y into map boundaries + if (minY < 0) + minY = 0; + if (minY >= TrueCraft.Core.World.World.Height) + minY = TrueCraft.Core.World.World.Height - 1; + if (maxY < 0) + maxY = 0; + if (maxY >= TrueCraft.Core.World.World.Height) + maxY = TrueCraft.Core.World.World.Height - 1; + + // Do terrain checks + double? collisionPoint = null; + BoundingBox blockBox; + for (int x = minX; x <= maxX; x++) + { + for (int y = minY; y <= maxY; y++) + { + for (int z = minZ; z <= maxZ; z++) + { + var position = new Coordinates3D(x, y, z); + if (!World.IsValidPosition(position)) + continue; + var boundingBox = BlockPhysicsProvider.GetBoundingBox(world.World, position); + if (boundingBox == null) + continue; + blockBox = boundingBox.Value.OffsetBy(position + new Vector3(0.5)); + if (TempBoundingBox.Intersects(blockBox)) + { + if (entity.Velocity.Y < 0) + { + if (!collisionPoint.HasValue) + collisionPoint = blockBox.Max.Y; + else if (collisionPoint.Value < blockBox.Max.Y) + collisionPoint = blockBox.Max.Y; + } + else + { + if (!collisionPoint.HasValue) + collisionPoint = blockBox.Min.Y; + else if (collisionPoint.Value > blockBox.Min.Y) + collisionPoint = blockBox.Min.Y; + } + collision = position; + } + } + } + } + + if (collisionPoint != null) + { + if (entity.Velocity.Y < 0) + { + // TODO: Do block event + //var block = world.GetBlock(collision); + //block.OnBlockWalkedOn(world, collision, this); + entity.Velocity = new Vector3(entity.Velocity.X, + entity.Velocity.Y + (collisionPoint.Value - TempBoundingBox.Min.Y), + entity.Velocity.Z); + collisionDirection = Vector3.Down; + } + else if (entity.Velocity.Y > 0) + { + entity.Velocity = new Vector3(entity.Velocity.X, + entity.Velocity.Y - (TempBoundingBox.Max.Y - collisionPoint.Value), + entity.Velocity.Z); + collisionDirection = Vector3.Up; + } + return true; + } + + return false; + } + + /// + /// Performs terrain collision tests and adjusts the Z-axis velocity accordingly + /// + /// True if the entity collides with the terrain + private bool AdjustVelocityZ(IAABBEntity entity, ReadOnlyWorld world, out Vector3 collision, out Vector3 collisionDirection) + { + collision = Vector3.Zero; + collisionDirection = Vector3.Zero; + if (entity.Velocity.Z == 0) + return false; + // Do some enviornment guessing to improve speed + int minX = (int)entity.Position.X - (entity.Position.X < 0 ? 1 : 0); + int maxX = (int)(entity.Position.X + entity.Size.Depth) - (entity.Position.X < 0 ? 1 : 0); + int minY = (int)entity.Position.Y - (entity.Position.Y < 0 ? 1 : 0); + int maxY = (int)(entity.Position.Y + entity.Size.Width) - (entity.Position.Y < 0 ? 1 : 0); + int minZ, maxZ; + + // Expand bounding box to include area to be tested + if (entity.Velocity.Z < 0) + { + TempBoundingBox = new BoundingBox( + new Vector3(entity.BoundingBox.Min.X, entity.BoundingBox.Min.Y, entity.BoundingBox.Min.Z + entity.Velocity.Z), + entity.BoundingBox.Max); + + maxZ = (int)(TempBoundingBox.Max.Z); + minZ = (int)(TempBoundingBox.Min.Z + entity.Velocity.Z) - 1; + } + else + { + TempBoundingBox = new BoundingBox( + entity.BoundingBox.Min, + new Vector3(entity.BoundingBox.Max.X, entity.BoundingBox.Max.Y, entity.BoundingBox.Max.Z + entity.Velocity.Z) + ); + minZ = (int)(entity.BoundingBox.Min.Z); + maxZ = (int)(entity.BoundingBox.Max.Z + entity.Velocity.Z) + 1; + } + + // Do terrain checks + double? collisionPoint = null; + BoundingBox blockBox; + for (int x = minX; x <= maxX; x++) + { + for (int y = minY; y <= maxY; y++) + { + for (int z = minZ; z <= maxZ; z++) + { + var position = new Coordinates3D(x, y, z); + var boundingBox = BlockPhysicsProvider.GetBoundingBox(world.World, position); + if (boundingBox == null) + continue; + blockBox = boundingBox.Value.OffsetBy(position + new Vector3(0.5)); + if (TempBoundingBox.Intersects(blockBox)) + { + if (entity.Velocity.Z < 0) + { + if (!collisionPoint.HasValue) + collisionPoint = blockBox.Max.Z; + else if (collisionPoint.Value < blockBox.Max.Z) + collisionPoint = blockBox.Max.Z; + } + else + { + if (!collisionPoint.HasValue) + collisionPoint = blockBox.Min.Z; + else if (collisionPoint.Value > blockBox.Min.Z) + collisionPoint = blockBox.Min.Z; + } + collision = position; + } + } + } + } + + if (collisionPoint != null) + { + if (entity.Velocity.Z < 0) + { + entity.Velocity = new Vector3( + entity.Velocity.X, + entity.Velocity.Y, + entity.Velocity.Z - (TempBoundingBox.Min.Z - collisionPoint.Value)); + collisionDirection = Vector3.Backwards; + } + else if (entity.Velocity.Z > 0) + { + entity.Velocity = new Vector3( + entity.Velocity.X, + entity.Velocity.Y, + entity.Velocity.Z - (TempBoundingBox.Max.Z - collisionPoint.Value)); + collisionDirection = Vector3.Forwards; + } + return true; + } + + return false; + } + } +} diff --git a/TrueCraft.Client.Linux/Program.cs b/TrueCraft.Client.Linux/Program.cs index cd05a90..cb7e980 100644 --- a/TrueCraft.Client.Linux/Program.cs +++ b/TrueCraft.Client.Linux/Program.cs @@ -13,6 +13,7 @@ namespace TrueCraft.Client.Linux var client = new MultiplayerClient(); var game = new TrueCraftGame(client, ParseEndPoint(args[0])); game.Run(); + client.Disconnect(); } private static IPEndPoint ParseEndPoint(string arg) diff --git a/TrueCraft.Client.Linux/ReadOnlyWorld.cs b/TrueCraft.Client.Linux/ReadOnlyWorld.cs index e48709e..5d48ffa 100644 --- a/TrueCraft.Client.Linux/ReadOnlyWorld.cs +++ b/TrueCraft.Client.Linux/ReadOnlyWorld.cs @@ -48,7 +48,14 @@ namespace TrueCraft.Client.Linux internal IChunk FindChunk(Coordinates2D coordinates) { - return World.FindChunk(new Coordinates3D(coordinates.X, 0, coordinates.Z)); + try + { + return World.FindChunk(new Coordinates3D(coordinates.X, 0, coordinates.Z)); + } + catch + { + return null; + } } public ReadOnlyChunk GetChunk(Coordinates2D coordinates) @@ -66,6 +73,11 @@ namespace TrueCraft.Client.Linux if (UnloadChunks) World.UnloadChunk(coordinates); } + + public bool IsValidPosition(Coordinates3D coords) + { + return World.IsValidPosition(coords); + } } public class ReadOnlyChunk diff --git a/TrueCraft.Client.Linux/TrueCraft.Client.Linux.csproj b/TrueCraft.Client.Linux/TrueCraft.Client.Linux.csproj index 5651d6b..6baadaf 100644 --- a/TrueCraft.Client.Linux/TrueCraft.Client.Linux.csproj +++ b/TrueCraft.Client.Linux/TrueCraft.Client.Linux.csproj @@ -37,6 +37,7 @@ bin\Client 4 127.0.0.1:25565 + true false @@ -71,6 +72,7 @@ + diff --git a/TrueCraft.Client.Linux/TrueCraftGame.cs b/TrueCraft.Client.Linux/TrueCraftGame.cs index cdc0b90..ab208aa 100644 --- a/TrueCraft.Client.Linux/TrueCraftGame.cs +++ b/TrueCraft.Client.Linux/TrueCraftGame.cs @@ -6,6 +6,7 @@ using System.Collections.Generic; using TrueCraft.Client.Linux.Interface; using System.IO; using System.Net; +using TrueCraft.API; namespace TrueCraft.Client.Linux { @@ -18,6 +19,7 @@ namespace TrueCraft.Client.Linux private SpriteBatch SpriteBatch { get; set; } private IPEndPoint EndPoint { get; set; } private ChunkConverter ChunkConverter { get; set; } + private DateTime NextPhysicsUpdate { get; set; } public TrueCraftGame(MultiplayerClient client, IPEndPoint endPoint) { @@ -31,6 +33,7 @@ namespace TrueCraft.Client.Linux EndPoint = endPoint; ChunkConverter = new ChunkConverter(); Client.ChunkLoaded += (sender, e) => ChunkConverter.QueueChunk(e.Chunk); + NextPhysicsUpdate = DateTime.MinValue; } protected override void Initialize() @@ -53,14 +56,44 @@ namespace TrueCraft.Client.Linux base.LoadContent(); } + protected override void OnExiting(object sender, EventArgs args) + { + ChunkConverter.Stop(); + base.OnExiting(sender, args); + } + + protected virtual void UpdateKeyboard(GameTime gameTime, KeyboardState state) + { + if (state.IsKeyDown(Keys.Escape)) + Exit(); + // TODO: Handle rotation + // TODO: Rebindable keys + // TODO: Horizontal terrain collisions + TrueCraft.API.Vector3 delta = TrueCraft.API.Vector3.Zero; + if (state.IsKeyDown(Keys.Left) || state.IsKeyDown(Keys.A)) + delta = TrueCraft.API.Vector3.Left; + if (state.IsKeyDown(Keys.Right) || state.IsKeyDown(Keys.D)) + delta = TrueCraft.API.Vector3.Right; + if (state.IsKeyDown(Keys.Up) || state.IsKeyDown(Keys.W)) + delta = TrueCraft.API.Vector3.Forwards; + if (state.IsKeyDown(Keys.Down) || state.IsKeyDown(Keys.S)) + delta = TrueCraft.API.Vector3.Backwards; + Client.Position += delta * (gameTime.ElapsedGameTime.TotalSeconds * 4.3717); // Note: 4.3717 is the speed of a Minecraft player in m/s + } + protected override void Update(GameTime gameTime) { - if (Keyboard.GetState().IsKeyDown(Keys.Escape)) - Exit(); foreach (var i in Interfaces) { i.Update(gameTime); } + if (NextPhysicsUpdate < DateTime.Now) + { + if (Client.World.FindChunk(new Coordinates2D((int)Client.Position.X, (int)Client.Position.Z)) != null) + Client.Physics.Update(); + NextPhysicsUpdate = DateTime.Now.AddMilliseconds(1000 / 20); + } + UpdateKeyboard(gameTime, Keyboard.GetState()); base.Update(gameTime); } diff --git a/TrueCraft/BlockRepository.cs b/TrueCraft.Core/Logic/BlockRepository.cs similarity index 95% rename from TrueCraft/BlockRepository.cs rename to TrueCraft.Core/Logic/BlockRepository.cs index 1ea0177..7fcb8ec 100644 --- a/TrueCraft/BlockRepository.cs +++ b/TrueCraft.Core/Logic/BlockRepository.cs @@ -6,7 +6,7 @@ using TrueCraft.API.Entities; using TrueCraft.API; using TrueCraft.API.World; -namespace TrueCraft +namespace TrueCraft.Core.Logic { public class BlockRepository : IBlockRepository, IBlockPhysicsProvider { @@ -22,7 +22,7 @@ namespace TrueCraft BlockProviders[provider.ID] = provider; } - internal void DiscoverBlockProviders() + public void DiscoverBlockProviders() { var providerTypes = new List(); foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) diff --git a/TrueCraft.Core/TrueCraft.Core.csproj b/TrueCraft.Core/TrueCraft.Core.csproj index a538648..a350d6d 100644 --- a/TrueCraft.Core/TrueCraft.Core.csproj +++ b/TrueCraft.Core/TrueCraft.Core.csproj @@ -320,6 +320,7 @@ + diff --git a/TrueCraft/EntityManager.cs b/TrueCraft/EntityManager.cs index 580cba7..fe9d79b 100644 --- a/TrueCraft/EntityManager.cs +++ b/TrueCraft/EntityManager.cs @@ -14,6 +14,7 @@ using TrueCraft.Core.World; using TrueCraft.API; using System.Collections.Concurrent; using TrueCraft.API.Logging; +using TrueCraft.Core.Logic; namespace TrueCraft { diff --git a/TrueCraft/MultiplayerServer.cs b/TrueCraft/MultiplayerServer.cs index 9f0c531..4768ab2 100644 --- a/TrueCraft/MultiplayerServer.cs +++ b/TrueCraft/MultiplayerServer.cs @@ -13,6 +13,7 @@ using TrueCraft.API; using TrueCraft.Core.Logging; using TrueCraft.API.Logic; using TrueCraft.Exceptions; +using TrueCraft.Core.Logic; namespace TrueCraft { diff --git a/TrueCraft/TrueCraft.csproj b/TrueCraft/TrueCraft.csproj index a518cc3..794acb6 100644 --- a/TrueCraft/TrueCraft.csproj +++ b/TrueCraft/TrueCraft.csproj @@ -69,12 +69,11 @@ - - +