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;
}
}