diff --git a/TrueCraft.API/Networking/IRemoteClient.cs b/TrueCraft.API/Networking/IRemoteClient.cs index 7540341..3fed5ff 100644 --- a/TrueCraft.API/Networking/IRemoteClient.cs +++ b/TrueCraft.API/Networking/IRemoteClient.cs @@ -17,8 +17,10 @@ namespace TrueCraft.API.Networking short SelectedSlot { get; } ItemStack SelectedItem { get; } IMultiplayerServer Server { get; } + bool EnableLogging { get; set; } void QueuePacket(IPacket packet); void SendMessage(string message); + void Log(string message, params object[] parameters); } } \ No newline at end of file diff --git a/TrueCraft.API/Server/IMultiplayerServer.cs b/TrueCraft.API/Server/IMultiplayerServer.cs index e37c229..ec25887 100644 --- a/TrueCraft.API/Server/IMultiplayerServer.cs +++ b/TrueCraft.API/Server/IMultiplayerServer.cs @@ -26,6 +26,7 @@ namespace TrueCraft.API.Server IBlockRepository BlockRepository { get; } IItemRepository ItemRepository { get; } bool BlockUpdatesEnabled { get; set; } + bool EnableClientLogging { get; set; } void Start(IPEndPoint endPoint); void RegisterPacketHandler(byte packetId, PacketHandler handler); diff --git a/TrueCraft.Core/Entities/PlayerEntity.cs b/TrueCraft.Core/Entities/PlayerEntity.cs index 4cc2736..1ddda14 100644 --- a/TrueCraft.Core/Entities/PlayerEntity.cs +++ b/TrueCraft.Core/Entities/PlayerEntity.cs @@ -49,6 +49,33 @@ namespace TrueCraft.Core.Entities public bool IsCrouching { get; set; } public double PositiveDeltaY { get; set; } + private Vector3 _OldPosition; + public Vector3 OldPosition + { + get + { + return _OldPosition; + } + private set + { + _OldPosition = value; + } + } + + public override Vector3 Position + { + get + { + return _Position; + } + set + { + _OldPosition = _Position; + _Position = value; + OnPropertyChanged("Position"); + } + } + protected short _SelectedSlot; public short SelectedSlot { diff --git a/TrueCraft.Core/Logic/BlockProvider.cs b/TrueCraft.Core/Logic/BlockProvider.cs index ed113f9..480a151 100644 --- a/TrueCraft.Core/Logic/BlockProvider.cs +++ b/TrueCraft.Core/Logic/BlockProvider.cs @@ -54,7 +54,6 @@ namespace TrueCraft.Core.Logic { if (!IsSupported(descriptor, server, world)) { - server.SendMessage(ChatColor.Red + "Removing block due to insufficient opaque support blocks"); GenerateDropEntity(descriptor, world, server); world.SetBlockID(descriptor.Coordinates, 0); } diff --git a/TrueCraft.Core/Logic/Blocks/BedBlock.cs b/TrueCraft.Core/Logic/Blocks/BedBlock.cs index 3e9a829..fc26faa 100644 --- a/TrueCraft.Core/Logic/Blocks/BedBlock.cs +++ b/TrueCraft.Core/Logic/Blocks/BedBlock.cs @@ -86,10 +86,7 @@ namespace TrueCraft.Core.Logic.Blocks public override void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world) { if (!ValidBedPosition(descriptor, server.BlockRepository, world)) - { world.SetBlockID(descriptor.Coordinates, 0); - server.SendMessage(ChatColor.Red + "Removing block due to insufficient neighboring bed blocks"); - } base.BlockUpdate(descriptor, server, world); } } diff --git a/TrueCraft/Commands/CommandManager.cs b/TrueCraft/Commands/CommandManager.cs index 3c81677..de7b4fb 100644 --- a/TrueCraft/Commands/CommandManager.cs +++ b/TrueCraft/Commands/CommandManager.cs @@ -25,6 +25,7 @@ namespace TrueCraft.Commands Commands.Add(new ResendInvCommand()); Commands.Add(new PositionCommand()); Commands.Add(new TimeCommand()); + Commands.Add(new LogCommand()); } /// diff --git a/TrueCraft/Commands/DebugCommands.cs b/TrueCraft/Commands/DebugCommands.cs index b928de0..dbe48dd 100644 --- a/TrueCraft/Commands/DebugCommands.cs +++ b/TrueCraft/Commands/DebugCommands.cs @@ -42,6 +42,39 @@ namespace TrueCraft.Commands } } + public class LogCommand : Command + { + public override string Name + { + get { return "log"; } + } + + public override string Description + { + get { return "Toggles client logging."; } + } + + public override string[] Aliases + { + get { return new string[0]; } + } + + public override void Handle(IRemoteClient Client, string Alias, string[] Arguments) + { + if (Arguments.Length != 0) + { + Help(Client, Alias, Arguments); + return; + } + Client.EnableLogging = !Client.EnableLogging; + } + + public override void Help(IRemoteClient Client, string Alias, string[] Arguments) + { + Client.SendMessage("/pos: Toggles client logging."); + } + } + public class TimeCommand : Command { public override string Name diff --git a/TrueCraft/EntityManager.cs b/TrueCraft/EntityManager.cs index 43cbda3..6c0abb8 100644 --- a/TrueCraft/EntityManager.cs +++ b/TrueCraft/EntityManager.cs @@ -28,8 +28,6 @@ namespace TrueCraft private object EntityLock = new object(); private ConcurrentBag PendingDespawns { get; set; } - private static readonly int MaxClientDistance = 4; - public EntityManager(IMultiplayerServer server, IWorld world) { Server = server; @@ -67,12 +65,60 @@ namespace TrueCraft switch (property) { case "Position": - // TODO: Only trigger this if the player crosses a chunk boundary - Task.Factory.StartNew(client.UpdateChunks); + if ((int)(entity.Position.X) >> 4 != (int)(entity.OldPosition.X) >> 4 || + (int)(entity.Position.Z) >> 4 != (int)(entity.OldPosition.Z) >> 4) + { + client.Log("Passed chunk boundary at {0}, {1}", (int)(entity.Position.X) >> 4, (int)(entity.Position.Z) >> 4); + Task.Factory.StartNew(client.UpdateChunks); + UpdateClientEntities(client); + } break; } } + internal void UpdateClientEntities(RemoteClient client) + { + var entity = client.Entity; + // Calculate entities you shouldn't know about anymore + for (int i = 0; i < client.KnownEntities.Count; i++) + { + var knownEntity = client.KnownEntities[i]; + if (knownEntity.Position.DistanceTo(entity.Position) > client.ChunkRadius * Chunk.Depth) + { + client.QueuePacket(new DestroyEntityPacket(knownEntity.EntityID)); + client.KnownEntities.Remove(knownEntity); + i--; + if (knownEntity is PlayerEntity) + { + var c = (RemoteClient)GetClientForEntity(knownEntity as PlayerEntity); + if (c.KnownEntities.Contains(entity)) + { + c.KnownEntities.Remove(entity); + c.QueuePacket(new DestroyEntityPacket(entity.EntityID)); + c.Log("Destroying entity {0} ({1})", knownEntity.EntityID, knownEntity.GetType().Name); + } + } + client.Log("Destroying entity {0} ({1})", knownEntity.EntityID, knownEntity.GetType().Name); + } + } + // Calculate entities you should now know about + var toSpawn = GetEntitiesInRange(entity, client.ChunkRadius); + foreach (var e in toSpawn) + { + if (e != entity && !client.KnownEntities.Contains(e)) + { + SendEntityToClient(client, e); + // Make sure other players know about you since you've moved + if (e is PlayerEntity) + { + var c = (RemoteClient)GetClientForEntity(e as PlayerEntity); + if (!c.KnownEntities.Contains(entity)) + SendEntityToClient(c, entity); + } + } + } + } + private void PropegateEntityPositionUpdates(IEntity entity) { for (int i = 0, ServerClientsCount = Server.Clients.Count; i < ServerClientsCount; i++) @@ -107,6 +153,7 @@ namespace TrueCraft private void SendEntityToClient(RemoteClient client, IEntity entity) { + client.Log("Spawning entity {0} ({1}) at {2}", entity.EntityID, entity.GetType().Name, (Coordinates3D)entity.Position); RemoteClient spawnedClient = null; if (entity is PlayerEntity) spawnedClient = (RemoteClient)GetClientForEntity(entity as PlayerEntity); @@ -153,7 +200,7 @@ namespace TrueCraft { Entities.Add(entity); } - foreach (var clientEntity in GetEntitiesInRange(entity, MaxClientDistance)) + foreach (var clientEntity in GetEntitiesInRange(entity, 8)) // Note: 8 is pretty arbitrary here { if (clientEntity != entity && clientEntity is PlayerEntity) { @@ -204,6 +251,8 @@ namespace TrueCraft if (client.KnownEntities.Contains(entity)) { client.QueuePacket(new DestroyEntityPacket(entity.EntityID)); + client.KnownEntities.Remove(entity); + client.Log("Destroying entity {0} ({1})", entity.EntityID, entity.GetType().Name); } } lock (EntityLock) @@ -219,7 +268,7 @@ namespace TrueCraft public void SendEntitiesToClient(IRemoteClient _client) { var client = _client as RemoteClient; - foreach (var entity in GetEntitiesInRange(client.Entity, MaxClientDistance)) + foreach (var entity in GetEntitiesInRange(client.Entity, client.ChunkRadius)) { if (entity != client.Entity) SendEntityToClient(client, entity); diff --git a/TrueCraft/MultiplayerServer.cs b/TrueCraft/MultiplayerServer.cs index d7096fb..b3f7f6f 100644 --- a/TrueCraft/MultiplayerServer.cs +++ b/TrueCraft/MultiplayerServer.cs @@ -28,6 +28,7 @@ namespace TrueCraft public IEventScheduler Scheduler { get; private set; } public IBlockRepository BlockRepository { get; private set; } public IItemRepository ItemRepository { get; private set; } + public bool EnableClientLogging { get; set; } private bool _BlockUpdatesEnabled = true; private struct BlockUpdate @@ -78,6 +79,7 @@ namespace TrueCraft itemRepository.DiscoverItemProviders(); ItemRepository = itemRepository; PendingBlockUpdates = new Queue(); + EnableClientLogging = false; reader.RegisterCorePackets(); Handlers.PacketHandlers.RegisterHandlers(this); diff --git a/TrueCraft/Program.cs b/TrueCraft/Program.cs index 6eccf90..23d450b 100644 --- a/TrueCraft/Program.cs +++ b/TrueCraft/Program.cs @@ -24,6 +24,7 @@ namespace TrueCraft server.AddLogProvider(new ConsoleLogProvider(LogCategory.Notice | LogCategory.Warning | LogCategory.Error | LogCategory.Debug)); #if DEBUG server.AddLogProvider(new FileLogProvider(new StreamWriter("packets.log", false), LogCategory.Packets)); + server.EnableClientLogging = true; #endif CommandManager = new CommandManager(); server.ChatMessageReceived += HandleChatMessageReceived; diff --git a/TrueCraft/RemoteClient.cs b/TrueCraft/RemoteClient.cs index 301e8e2..3efbe3e 100644 --- a/TrueCraft/RemoteClient.cs +++ b/TrueCraft/RemoteClient.cs @@ -36,6 +36,7 @@ namespace TrueCraft ItemStaging = ItemStack.EmptyStack; KnownEntities = new List(); Disconnected = false; + EnableLogging = server.EnableClientLogging; } /// @@ -55,6 +56,7 @@ namespace TrueCraft public short SelectedSlot { get; internal set; } public ItemStack ItemStaging { get; set; } public IWindow CurrentWindow { get; set; } + public bool EnableLogging { get; set; } private IEntity _Entity; public IEntity Entity @@ -112,6 +114,12 @@ namespace TrueCraft } } + public void Log(string message, params object[] parameters) + { + if (EnableLogging) + SendMessage(ChatColor.Gray + string.Format("[" + DateTime.Now.ToShortTimeString() + "] " + message, parameters)); + } + public void QueuePacket(IPacket packet) { PacketQueue.Enqueue(packet); @@ -166,6 +174,7 @@ namespace TrueCraft LoadChunk(chunk); } } + ((EntityManager)Server.GetEntityManagerForWorld(World)).UpdateClientEntities(this); } internal void UnloadAllChunks()