diff --git a/TrueCraft.API/World/BlockDescriptor.cs b/TrueCraft.API/Logic/BlockDescriptor.cs similarity index 88% rename from TrueCraft.API/World/BlockDescriptor.cs rename to TrueCraft.API/Logic/BlockDescriptor.cs index f524a19..5d6db36 100644 --- a/TrueCraft.API/World/BlockDescriptor.cs +++ b/TrueCraft.API/Logic/BlockDescriptor.cs @@ -1,6 +1,6 @@ using System; -namespace TrueCraft.API.World +namespace TrueCraft.API.Logic { public struct BlockDescriptor { diff --git a/TrueCraft.API/Logic/IBlockProvider.cs b/TrueCraft.API/Logic/IBlockProvider.cs index 988623b..2456c56 100644 --- a/TrueCraft.API/Logic/IBlockProvider.cs +++ b/TrueCraft.API/Logic/IBlockProvider.cs @@ -1,6 +1,7 @@ using System; using TrueCraft.API.World; using TrueCraft.API.Networking; +using TrueCraft.API.Server; namespace TrueCraft.API.Logic { @@ -17,7 +18,7 @@ namespace TrueCraft.API.Logic bool BlockRightClicked(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user); bool BlockPlaced(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user); void BlockMined(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user); - void BlockUpdate(BlockDescriptor descriptor, IWorld world); + void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world); void BlockScheduledEvent(BlockDescriptor descriptor, IWorld world, object data); } } \ No newline at end of file diff --git a/TrueCraft.API/Logic/IItemProvider.cs b/TrueCraft.API/Logic/IItemProvider.cs index 50c0c56..c9cad68 100644 --- a/TrueCraft.API/Logic/IItemProvider.cs +++ b/TrueCraft.API/Logic/IItemProvider.cs @@ -1,4 +1,7 @@ using System; +using TrueCraft.API.World; +using TrueCraft.API.Networking; +using TrueCraft.API.Entities; namespace TrueCraft.API.Logic { @@ -7,6 +10,8 @@ namespace TrueCraft.API.Logic short ID { get; } sbyte MaximumStack { get; } string DisplayName { get; } - //bool ItemUsedOnBlock(ItemDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user); + void ItemUsedOnNothing(ItemStack item, IWorld world, IRemoteClient user); + void ItemUsedOnEntity(ItemStack item, IEntity usedOn, IWorld world, IRemoteClient user); + void ItemUsedOnBlock(Coordinates3D coordinates, ItemStack item, BlockFace face, IWorld world, IRemoteClient user); } } \ No newline at end of file diff --git a/TrueCraft.API/Server/IMultiplayerServer.cs b/TrueCraft.API/Server/IMultiplayerServer.cs index cbd3a99..e37c229 100644 --- a/TrueCraft.API/Server/IMultiplayerServer.cs +++ b/TrueCraft.API/Server/IMultiplayerServer.cs @@ -25,6 +25,7 @@ namespace TrueCraft.API.Server IEventScheduler Scheduler { get; } IBlockRepository BlockRepository { get; } IItemRepository ItemRepository { get; } + bool BlockUpdatesEnabled { get; set; } void Start(IPEndPoint endPoint); void RegisterPacketHandler(byte packetId, PacketHandler handler); diff --git a/TrueCraft.API/TrueCraft.API.csproj b/TrueCraft.API/TrueCraft.API.csproj index 73a3a64..0207950 100644 --- a/TrueCraft.API/TrueCraft.API.csproj +++ b/TrueCraft.API/TrueCraft.API.csproj @@ -79,11 +79,11 @@ - + diff --git a/TrueCraft.API/World/BlockChangeEventArgs.cs b/TrueCraft.API/World/BlockChangeEventArgs.cs index f527347..c331dc3 100644 --- a/TrueCraft.API/World/BlockChangeEventArgs.cs +++ b/TrueCraft.API/World/BlockChangeEventArgs.cs @@ -1,4 +1,5 @@ using System; +using TrueCraft.API.Logic; namespace TrueCraft.API.World { diff --git a/TrueCraft.API/World/IWorld.cs b/TrueCraft.API/World/IWorld.cs index 1b1bd13..23ff9cd 100644 --- a/TrueCraft.API/World/IWorld.cs +++ b/TrueCraft.API/World/IWorld.cs @@ -1,4 +1,5 @@ using System; +using TrueCraft.API.Logic; namespace TrueCraft.API.World { @@ -19,6 +20,7 @@ namespace TrueCraft.API.World byte GetMetadata(Coordinates3D coordinates); byte GetSkyLight(Coordinates3D coordinates); BlockDescriptor GetBlockData(Coordinates3D coordinates); + void SetBlockData(Coordinates3D coordinates, BlockDescriptor block); void SetBlockID(Coordinates3D coordinates, byte value); void SetMetadata(Coordinates3D coordinates, byte value); void SetSkyLight(Coordinates3D coordinates, byte value); diff --git a/TrueCraft.Core/Entities/ItemEntity.cs b/TrueCraft.Core/Entities/ItemEntity.cs index 57a2725..7432c80 100644 --- a/TrueCraft.Core/Entities/ItemEntity.cs +++ b/TrueCraft.Core/Entities/ItemEntity.cs @@ -19,6 +19,8 @@ namespace TrueCraft.Core.Entities { Position = position; Item = item; + if (Item.ID == 0) + System.Diagnostics.Debugger.Break(); } public ItemStack Item { get; set; } diff --git a/TrueCraft.Core/Logic/BlockProvider.cs b/TrueCraft.Core/Logic/BlockProvider.cs index 57884a3..ed113f9 100644 --- a/TrueCraft.Core/Logic/BlockProvider.cs +++ b/TrueCraft.Core/Logic/BlockProvider.cs @@ -4,13 +4,15 @@ using TrueCraft.API.World; using TrueCraft.API; using TrueCraft.API.Networking; using TrueCraft.Core.Entities; +using TrueCraft.API.Entities; +using TrueCraft.API.Server; namespace TrueCraft.Core.Logic { /// /// Provides common implementations of block logic. /// - public abstract class BlockProvider : IBlockProvider, IItemProvider + public abstract class BlockProvider : IItemProvider, IBlockProvider { public virtual bool BlockRightClicked(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user) { @@ -24,18 +26,38 @@ namespace TrueCraft.Core.Logic public virtual void BlockMined(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user) { - var entityManager = user.Server.GetEntityManagerForWorld(world); - var items = GetDrop(descriptor); - foreach (var item in items) - { - entityManager.SpawnEntity(new ItemEntity(new Vector3(descriptor.Coordinates) + new Vector3(0.5), item)); - } + GenerateDropEntity(descriptor, world, user.Server); world.SetBlockID(descriptor.Coordinates, 0); } - public virtual void BlockUpdate(BlockDescriptor descriptor, IWorld world) + private void GenerateDropEntity(BlockDescriptor descriptor, IWorld world, IMultiplayerServer server) { - // This space intentionally left blank + var entityManager = server.GetEntityManagerForWorld(world); + var items = GetDrop(descriptor); + foreach (var item in items) + entityManager.SpawnEntity(new ItemEntity(new Vector3(descriptor.Coordinates) + new Vector3(0.5), item)); + } + + public virtual bool IsSupported(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world) + { + var support = GetSupportDirection(descriptor); + if (support != Coordinates3D.Zero) + { + var supportingBlock = server.BlockRepository.GetBlockProvider(world.GetBlockID(descriptor.Coordinates + support)); + if (!supportingBlock.Opaque) + return false; + } + return true; + } + + public virtual void BlockUpdate(BlockDescriptor descriptor, IMultiplayerServer server, IWorld world) + { + 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); + } } public virtual void BlockScheduledEvent(BlockDescriptor descriptor, IWorld world, object data) @@ -48,6 +70,25 @@ namespace TrueCraft.Core.Logic return new[] { new ItemStack(descriptor.ID, 1, descriptor.Metadata) }; } + public virtual void ItemUsedOnEntity(ItemStack item, IEntity usedOn, IWorld world, IRemoteClient user) + { + // This space intentionally left blank + } + + public virtual void ItemUsedOnNothing(ItemStack item, IWorld world, IRemoteClient user) + { + // This space intentionally left blank + } + + public virtual void ItemUsedOnBlock(Coordinates3D coordinates, ItemStack item, BlockFace face, IWorld world, IRemoteClient user) + { + coordinates += MathHelper.BlockFaceToCoordinates(face); + world.SetBlockID(coordinates, (byte)item.ID); + world.SetMetadata(coordinates, (byte)item.Metadata); + item.Count--; + user.Inventory[user.SelectedSlot] = item; + } + short IItemProvider.ID { get @@ -61,6 +102,11 @@ namespace TrueCraft.Core.Logic /// public abstract byte ID { get; } + public virtual Coordinates3D GetSupportDirection(BlockDescriptor descriptor) + { + return Coordinates3D.Zero; + } + /// /// The maximum amount that can be in a single stack of this block. /// diff --git a/TrueCraft.Core/Logic/Blocks/AirBlock.cs b/TrueCraft.Core/Logic/Blocks/AirBlock.cs new file mode 100644 index 0000000..f9b8c72 --- /dev/null +++ b/TrueCraft.Core/Logic/Blocks/AirBlock.cs @@ -0,0 +1,26 @@ +using System; + +namespace TrueCraft.Core.Logic.Blocks +{ + public class AirBlock : BlockProvider + { + public static readonly byte BlockID = 0x00; + + public override byte ID { get { return 0x00; } } + + public override double BlastResistance { get { return 0; } } + + public override double Hardness { get { return 100000; } } + + public override bool Opaque { get { return false; } } + + public override byte Luminance { get { return 0; } } + + public override string DisplayName { get { return "Air"; } } + + public override Tuple GetTextureMap(byte metadata) + { + return new Tuple(0, 0); + } + } +} \ No newline at end of file diff --git a/TrueCraft.Core/Logic/Blocks/BedBlock.cs b/TrueCraft.Core/Logic/Blocks/BedBlock.cs index 7ac1390..3e9a829 100644 --- a/TrueCraft.Core/Logic/Blocks/BedBlock.cs +++ b/TrueCraft.Core/Logic/Blocks/BedBlock.cs @@ -1,10 +1,30 @@ using System; using TrueCraft.API.Logic; +using TrueCraft.API; +using TrueCraft.Core.Logic.Items; +using TrueCraft.API.World; +using TrueCraft.API.Server; namespace TrueCraft.Core.Logic.Blocks { public class BedBlock : BlockProvider { + [Flags] + public enum BedDirection : byte + { + South = 0x0, + West = 0x1, + North = 0x2, + East = 0x3, + } + + [Flags] + public enum BedType : byte + { + Foot = 0x0, + Head = 0x8, + } + public static readonly byte BlockID = 0x1A; public override byte ID { get { return 0x1A; } } @@ -23,5 +43,54 @@ namespace TrueCraft.Core.Logic.Blocks { return new Tuple(6, 8); } + + protected override ItemStack[] GetDrop(BlockDescriptor descriptor) + { + return new[] { new ItemStack(BedItem.ItemID) }; + } + + public bool ValidBedPosition(BlockDescriptor descriptor, IBlockRepository repository, IWorld world, bool checkNeighbor = true, bool checkSupport = false) + { + if (checkNeighbor) + { + var other = Coordinates3D.Zero; + switch ((BedDirection)(descriptor.Metadata & 0x3)) + { + case BedDirection.East: + other = Coordinates3D.East; + break; + case BedDirection.West: + other = Coordinates3D.West; + break; + case BedDirection.North: + other = Coordinates3D.North; + break; + case BedDirection.South: + other = Coordinates3D.South; + break; + } + if ((descriptor.Metadata & (byte)BedType.Head) == (byte)BedType.Head) + other = -other; + if (world.GetBlockID(descriptor.Coordinates + other) != BedBlock.BlockID) + return false; + } + if (checkSupport) + { + var supportingBlock = repository.GetBlockProvider(world.GetBlockID(descriptor.Coordinates + Coordinates3D.Down)); + if (!supportingBlock.Opaque) + return false; + } + return true; + } + + 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); + } } } \ No newline at end of file diff --git a/TrueCraft.Core/Logic/Blocks/GrassBlock.cs b/TrueCraft.Core/Logic/Blocks/GrassBlock.cs index 80af5d1..202d042 100644 --- a/TrueCraft.Core/Logic/Blocks/GrassBlock.cs +++ b/TrueCraft.Core/Logic/Blocks/GrassBlock.cs @@ -17,8 +17,6 @@ namespace TrueCraft.Core.Logic.Blocks public override byte Luminance { get { return 0; } } - public override bool Opaque { get { return false; } } - public override string DisplayName { get { return "Grass"; } } public override Tuple GetTextureMap(byte metadata) diff --git a/TrueCraft.Core/Logic/ItemProvider.cs b/TrueCraft.Core/Logic/ItemProvider.cs index 429281f..4acfb96 100644 --- a/TrueCraft.Core/Logic/ItemProvider.cs +++ b/TrueCraft.Core/Logic/ItemProvider.cs @@ -4,6 +4,9 @@ using System.Linq; using System.Text; using TrueCraft.API.Logic; using TrueCraft.API; +using TrueCraft.API.Entities; +using TrueCraft.API.World; +using TrueCraft.API.Networking; namespace TrueCraft.Core.Logic { @@ -14,5 +17,20 @@ namespace TrueCraft.Core.Logic public virtual sbyte MaximumStack { get { return 64; } } public virtual string DisplayName { get { return string.Empty; } } + + public virtual void ItemUsedOnEntity(ItemStack item, IEntity usedOn, IWorld world, IRemoteClient user) + { + // This space intentionally left blank + } + + public virtual void ItemUsedOnBlock(Coordinates3D coordinates, ItemStack item, BlockFace face, IWorld world, IRemoteClient user) + { + // This space intentionally left blank + } + + public virtual void ItemUsedOnNothing(ItemStack item, IWorld world, IRemoteClient user) + { + // This space intentionally left blank + } } } \ No newline at end of file diff --git a/TrueCraft.Core/Logic/Items/BedItem.cs b/TrueCraft.Core/Logic/Items/BedItem.cs index 3fd7b9d..3292f31 100644 --- a/TrueCraft.Core/Logic/Items/BedItem.cs +++ b/TrueCraft.Core/Logic/Items/BedItem.cs @@ -1,5 +1,9 @@ using System; using TrueCraft.API.Logic; +using TrueCraft.API; +using TrueCraft.API.World; +using TrueCraft.API.Networking; +using TrueCraft.Core.Logic.Blocks; namespace TrueCraft.Core.Logic.Items { @@ -12,5 +16,48 @@ namespace TrueCraft.Core.Logic.Items public override sbyte MaximumStack { get { return 1; } } public override string DisplayName { get { return "Bed"; } } + + public override void ItemUsedOnBlock(Coordinates3D coordinates, ItemStack item, BlockFace face, IWorld world, IRemoteClient user) + { + coordinates += MathHelper.BlockFaceToCoordinates(face); + var head = coordinates; + var foot = coordinates; + BedBlock.BedDirection direction = BedBlock.BedDirection.North; + switch (MathHelper.DirectionByRotationFlat(user.Entity.Yaw)) + { + case Direction.North: + head += Coordinates3D.North; + direction = BedBlock.BedDirection.North; + break; + case Direction.South: + head += Coordinates3D.South; + direction = BedBlock.BedDirection.South; + break; + case Direction.East: + head += Coordinates3D.East; + direction = BedBlock.BedDirection.East; + break; + case Direction.West: + head += Coordinates3D.West; + direction = BedBlock.BedDirection.West; + break; + } + var bedProvider = (BedBlock)user.Server.BlockRepository.GetBlockProvider(BedBlock.BlockID); + if (!bedProvider.ValidBedPosition(new BlockDescriptor { Coordinates = head }, + user.Server.BlockRepository, user.World, false, true) || + !bedProvider.ValidBedPosition(new BlockDescriptor { Coordinates = foot }, + user.Server.BlockRepository, user.World, false, true)) + { + return; + } + user.Server.BlockUpdatesEnabled = false; + world.SetBlockData(head, new BlockDescriptor + { ID = BedBlock.BlockID, Metadata = (byte)((byte)direction | (byte)BedBlock.BedType.Head) }); + world.SetBlockData(foot, new BlockDescriptor + { ID = BedBlock.BlockID, Metadata = (byte)((byte)direction | (byte)BedBlock.BedType.Foot) }); + user.Server.BlockUpdatesEnabled = true; + item.Count--; + user.Inventory[user.SelectedSlot] = item; + } } } \ No newline at end of file diff --git a/TrueCraft.Core/TrueCraft.Core.csproj b/TrueCraft.Core/TrueCraft.Core.csproj index 7c58f8b..0bae5a3 100644 --- a/TrueCraft.Core/TrueCraft.Core.csproj +++ b/TrueCraft.Core/TrueCraft.Core.csproj @@ -267,6 +267,7 @@ + diff --git a/TrueCraft.Core/World/World.cs b/TrueCraft.Core/World/World.cs index 9194764..3549ee5 100644 --- a/TrueCraft.Core/World/World.cs +++ b/TrueCraft.Core/World/World.cs @@ -5,6 +5,7 @@ using System.IO; using System.Threading; using TrueCraft.API; using TrueCraft.API.World; +using TrueCraft.API.Logic; namespace TrueCraft.Core.World { @@ -159,6 +160,18 @@ namespace TrueCraft.Core.World return GetBlockDataFromChunk(adjustedCoordinates, chunk, coordinates); } + public void SetBlockData(Coordinates3D coordinates, BlockDescriptor descriptor) + { + // TODO: Figure out the best way to handle light in this scenario + IChunk chunk; + var adjustedCoordinates = FindBlockPosition(coordinates, out chunk); + var old = GetBlockDataFromChunk(adjustedCoordinates, chunk, coordinates); + chunk.SetBlockID(adjustedCoordinates, descriptor.ID); + chunk.SetMetadata(adjustedCoordinates,descriptor.Metadata); + if (BlockChanged != null) + BlockChanged(this, new BlockChangeEventArgs(coordinates, old, GetBlockDataFromChunk(adjustedCoordinates, chunk, coordinates))); + } + private BlockDescriptor GetBlockDataFromChunk(Coordinates3D adjustedCoordinates, IChunk chunk, Coordinates3D coordinates) { return new BlockDescriptor diff --git a/TrueCraft/Handlers/InteractionHandlers.cs b/TrueCraft/Handlers/InteractionHandlers.cs index 0dd2d5e..3855ac2 100644 --- a/TrueCraft/Handlers/InteractionHandlers.cs +++ b/TrueCraft/Handlers/InteractionHandlers.cs @@ -6,6 +6,7 @@ using TrueCraft.API; using TrueCraft.API.World; using TrueCraft.Core; using TrueCraft.Core.Windows; +using TrueCraft.API.Logic; namespace TrueCraft.Handlers { @@ -43,7 +44,7 @@ namespace TrueCraft.Handlers if (c.KnownEntities.Contains(client.Entity)) c.QueuePacket(new AnimationPacket(client.Entity.EntityID, AnimationPacket.PlayerAnimation.None)); } - if (provider != null) + if (provider != null && descriptor.ID != 0) provider.BlockMined(descriptor, packet.Face, world, client); break; } @@ -93,16 +94,17 @@ namespace TrueCraft.Handlers { if (use) { - // Temporary: just place the damn thing - position += MathHelper.BlockFaceToCoordinates(packet.Face); - client.World.SetBlockID(position, (byte)slot.ID); - client.World.SetMetadata(position, (byte)slot.Metadata); - slot.Count--; - client.Inventory[client.SelectedSlot] = slot; - // End temporary + var itemProvider = server.ItemRepository.GetItemProvider(slot.ID); + if (itemProvider == null) + { + server.SendMessage(ChatColor.Red + "WARNING: item provider for ID {0} is null (player placing)", block.Value.ID); + server.SendMessage(ChatColor.Red + "Error occured from client {0} at coordinates {1}", client.Username, block.Value.Coordinates); + server.SendMessage(ChatColor.Red + "Packet logged at {0}, please report upstream", DateTime.Now); + } if (block != null) { - // TODO: Use item on block + if (itemProvider != null) + itemProvider.ItemUsedOnBlock(position, slot, packet.Face, client.World, client); } else { diff --git a/TrueCraft/ItemRepository.cs b/TrueCraft/ItemRepository.cs index cea01e6..04ab8d1 100644 --- a/TrueCraft/ItemRepository.cs +++ b/TrueCraft/ItemRepository.cs @@ -19,16 +19,11 @@ namespace TrueCraft public IItemProvider GetItemProvider(short id) { - int max = ItemProviders.Count - 1, min = 0; - while (max >= min) + // TODO: Binary search + for (int i = 0; i < ItemProviders.Count; i++) { - int mid = (max - min / 2) + min; - if (ItemProviders[mid].ID == id) - return ItemProviders[mid]; - else if(ItemProviders[mid].ID < id) - min = mid + 1; - else - max = min - 1; + if (ItemProviders[i].ID == id) + return ItemProviders[i]; } return null; } diff --git a/TrueCraft/MultiplayerServer.cs b/TrueCraft/MultiplayerServer.cs index 84db2c5..d7096fb 100644 --- a/TrueCraft/MultiplayerServer.cs +++ b/TrueCraft/MultiplayerServer.cs @@ -29,11 +29,35 @@ namespace TrueCraft public IBlockRepository BlockRepository { get; private set; } public IItemRepository ItemRepository { get; private set; } + private bool _BlockUpdatesEnabled = true; + private struct BlockUpdate + { + public Coordinates3D Coordinates; + public IWorld World; + } + private Queue PendingBlockUpdates { get; set; } + public bool BlockUpdatesEnabled + { + get + { + return _BlockUpdatesEnabled; + } + set + { + _BlockUpdatesEnabled = value; + if (_BlockUpdatesEnabled) + { + ProcessBlockUpdates(); + } + } + } + private Timer EnvironmentWorker; private Thread NetworkWorker; private TcpListener Listener; private readonly PacketHandler[] PacketHandlers; private IList LogProviders; + private object ClientLock = new object(); public MultiplayerServer() { @@ -53,6 +77,7 @@ namespace TrueCraft var itemRepository = new ItemRepository(); itemRepository.DiscoverItemProviders(); ItemRepository = itemRepository; + PendingBlockUpdates = new Queue(); reader.RegisterCorePackets(); Handlers.PacketHandlers.RegisterHandlers(this); @@ -90,7 +115,32 @@ namespace TrueCraft if (client.LoggedIn && client.World == sender) { client.QueuePacket(new BlockChangePacket(e.Position.X, (sbyte)e.Position.Y, e.Position.Z, - (sbyte)e.NewBlock.ID, (sbyte)e.NewBlock.Metadata)); + (sbyte)e.NewBlock.ID, (sbyte)e.NewBlock.Metadata)); + } + } + PendingBlockUpdates.Enqueue(new BlockUpdate { Coordinates = e.Position, World = sender as IWorld }); + ProcessBlockUpdates(); + } + + private void ProcessBlockUpdates() + { + if (!BlockUpdatesEnabled) + return; + var adjacent = new[] + { + Coordinates3D.Up, Coordinates3D.Down, + Coordinates3D.Left, Coordinates3D.Right, + Coordinates3D.Forwards, Coordinates3D.Backwards + }; + while (PendingBlockUpdates.Count != 0) + { + var update = PendingBlockUpdates.Dequeue(); + foreach (var offset in adjacent) + { + var descriptor = update.World.GetBlockData(update.Coordinates + offset); + var provider = BlockRepository.GetBlockProvider(descriptor.ID); + if (provider != null) + provider.BlockUpdate(descriptor, this, update.World); } } } @@ -164,7 +214,8 @@ namespace TrueCraft { var tcpClient = Listener.EndAcceptTcpClient(result); var client = new RemoteClient(this, tcpClient.GetStream()); - Clients.Add(client); + lock (ClientLock) + Clients.Add(client); Listener.BeginAcceptTcpClient(AcceptClient, null); } @@ -184,11 +235,17 @@ namespace TrueCraft bool idle = true; for (int i = 0; i < Clients.Count && i >= 0; i++) { - Console.WriteLine("Running update " + DateTime.Now); - var client = Clients[i] as RemoteClient; - var sendTimeout = DateTime.Now.AddMilliseconds(50); - while (client.PacketQueue.Count != 0 && DateTime.Now < sendTimeout) + RemoteClient client; + lock (ClientLock) + client = Clients[i] as RemoteClient; + var sendTimeout = DateTime.Now.AddMilliseconds(100); + while (client.PacketQueue.Count != 0) { + if (DateTime.Now > sendTimeout) + { + Console.WriteLine("Send timeout" + DateTime.Now); + break; + } idle = false; try { @@ -225,9 +282,14 @@ namespace TrueCraft Clients.RemoveAt(i); break; } - var receiveTimeout = DateTime.Now.AddMilliseconds(50); - while (client.DataAvailable && DateTime.Now < receiveTimeout) + var receiveTimeout = DateTime.Now.AddMilliseconds(100); + while (client.DataAvailable) { + if (DateTime.Now > receiveTimeout) + { + Console.WriteLine("Receive timeout" + DateTime.Now); + break; + } idle = false; var packet = PacketReader.ReadPacket(client.MinecraftStream); LogPacket(packet, true); @@ -268,7 +330,8 @@ namespace TrueCraft Thread.Sleep(100); if (client.Disconnected) { - Clients.RemoveAt(i); + lock (ClientLock) + Clients.RemoveAt(i); break; } }