Implement bed placement and supported blocks

This commit is contained in:
Drew DeVault 2015-02-01 18:53:10 -07:00
parent 91fdf59532
commit eda5dd2f82
19 changed files with 332 additions and 42 deletions

View File

@ -1,6 +1,6 @@
using System; using System;
namespace TrueCraft.API.World namespace TrueCraft.API.Logic
{ {
public struct BlockDescriptor public struct BlockDescriptor
{ {

View File

@ -1,6 +1,7 @@
using System; using System;
using TrueCraft.API.World; using TrueCraft.API.World;
using TrueCraft.API.Networking; using TrueCraft.API.Networking;
using TrueCraft.API.Server;
namespace TrueCraft.API.Logic namespace TrueCraft.API.Logic
{ {
@ -17,7 +18,7 @@ namespace TrueCraft.API.Logic
bool BlockRightClicked(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user); bool BlockRightClicked(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user);
bool BlockPlaced(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 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); void BlockScheduledEvent(BlockDescriptor descriptor, IWorld world, object data);
} }
} }

View File

@ -1,4 +1,7 @@
using System; using System;
using TrueCraft.API.World;
using TrueCraft.API.Networking;
using TrueCraft.API.Entities;
namespace TrueCraft.API.Logic namespace TrueCraft.API.Logic
{ {
@ -7,6 +10,8 @@ namespace TrueCraft.API.Logic
short ID { get; } short ID { get; }
sbyte MaximumStack { get; } sbyte MaximumStack { get; }
string DisplayName { 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);
} }
} }

View File

@ -25,6 +25,7 @@ namespace TrueCraft.API.Server
IEventScheduler Scheduler { get; } IEventScheduler Scheduler { get; }
IBlockRepository BlockRepository { get; } IBlockRepository BlockRepository { get; }
IItemRepository ItemRepository { get; } IItemRepository ItemRepository { get; }
bool BlockUpdatesEnabled { get; set; }
void Start(IPEndPoint endPoint); void Start(IPEndPoint endPoint);
void RegisterPacketHandler(byte packetId, PacketHandler handler); void RegisterPacketHandler(byte packetId, PacketHandler handler);

View File

@ -79,11 +79,11 @@
<Compile Include="BlockFace.cs" /> <Compile Include="BlockFace.cs" />
<Compile Include="Server\PlayerJoinedEventArgs.cs" /> <Compile Include="Server\PlayerJoinedEventArgs.cs" />
<Compile Include="Logic\IBlockRepository.cs" /> <Compile Include="Logic\IBlockRepository.cs" />
<Compile Include="World\BlockDescriptor.cs" />
<Compile Include="Entities\IAABBEntity.cs" /> <Compile Include="Entities\IAABBEntity.cs" />
<Compile Include="Entities\IBlockPhysicsProvider.cs" /> <Compile Include="Entities\IBlockPhysicsProvider.cs" />
<Compile Include="Entities\IPhysicsEntity.cs" /> <Compile Include="Entities\IPhysicsEntity.cs" />
<Compile Include="Logic\IItemRepository.cs" /> <Compile Include="Logic\IItemRepository.cs" />
<Compile Include="Logic\BlockDescriptor.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup /> <ItemGroup />

View File

@ -1,4 +1,5 @@
using System; using System;
using TrueCraft.API.Logic;
namespace TrueCraft.API.World namespace TrueCraft.API.World
{ {

View File

@ -1,4 +1,5 @@
using System; using System;
using TrueCraft.API.Logic;
namespace TrueCraft.API.World namespace TrueCraft.API.World
{ {
@ -19,6 +20,7 @@ namespace TrueCraft.API.World
byte GetMetadata(Coordinates3D coordinates); byte GetMetadata(Coordinates3D coordinates);
byte GetSkyLight(Coordinates3D coordinates); byte GetSkyLight(Coordinates3D coordinates);
BlockDescriptor GetBlockData(Coordinates3D coordinates); BlockDescriptor GetBlockData(Coordinates3D coordinates);
void SetBlockData(Coordinates3D coordinates, BlockDescriptor block);
void SetBlockID(Coordinates3D coordinates, byte value); void SetBlockID(Coordinates3D coordinates, byte value);
void SetMetadata(Coordinates3D coordinates, byte value); void SetMetadata(Coordinates3D coordinates, byte value);
void SetSkyLight(Coordinates3D coordinates, byte value); void SetSkyLight(Coordinates3D coordinates, byte value);

View File

@ -19,6 +19,8 @@ namespace TrueCraft.Core.Entities
{ {
Position = position; Position = position;
Item = item; Item = item;
if (Item.ID == 0)
System.Diagnostics.Debugger.Break();
} }
public ItemStack Item { get; set; } public ItemStack Item { get; set; }

View File

@ -4,13 +4,15 @@ using TrueCraft.API.World;
using TrueCraft.API; using TrueCraft.API;
using TrueCraft.API.Networking; using TrueCraft.API.Networking;
using TrueCraft.Core.Entities; using TrueCraft.Core.Entities;
using TrueCraft.API.Entities;
using TrueCraft.API.Server;
namespace TrueCraft.Core.Logic namespace TrueCraft.Core.Logic
{ {
/// <summary> /// <summary>
/// Provides common implementations of block logic. /// Provides common implementations of block logic.
/// </summary> /// </summary>
public abstract class BlockProvider : IBlockProvider, IItemProvider public abstract class BlockProvider : IItemProvider, IBlockProvider
{ {
public virtual bool BlockRightClicked(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user) 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) public virtual void BlockMined(BlockDescriptor descriptor, BlockFace face, IWorld world, IRemoteClient user)
{ {
var entityManager = user.Server.GetEntityManagerForWorld(world); GenerateDropEntity(descriptor, world, user.Server);
var items = GetDrop(descriptor);
foreach (var item in items)
{
entityManager.SpawnEntity(new ItemEntity(new Vector3(descriptor.Coordinates) + new Vector3(0.5), item));
}
world.SetBlockID(descriptor.Coordinates, 0); 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) 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) }; 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 short IItemProvider.ID
{ {
get get
@ -61,6 +102,11 @@ namespace TrueCraft.Core.Logic
/// </summary> /// </summary>
public abstract byte ID { get; } public abstract byte ID { get; }
public virtual Coordinates3D GetSupportDirection(BlockDescriptor descriptor)
{
return Coordinates3D.Zero;
}
/// <summary> /// <summary>
/// The maximum amount that can be in a single stack of this block. /// The maximum amount that can be in a single stack of this block.
/// </summary> /// </summary>

View File

@ -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<int, int> GetTextureMap(byte metadata)
{
return new Tuple<int, int>(0, 0);
}
}
}

View File

@ -1,10 +1,30 @@
using System; using System;
using TrueCraft.API.Logic; 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 namespace TrueCraft.Core.Logic.Blocks
{ {
public class BedBlock : BlockProvider 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 static readonly byte BlockID = 0x1A;
public override byte ID { get { return 0x1A; } } public override byte ID { get { return 0x1A; } }
@ -23,5 +43,54 @@ namespace TrueCraft.Core.Logic.Blocks
{ {
return new Tuple<int, int>(6, 8); return new Tuple<int, int>(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);
}
} }
} }

View File

@ -17,8 +17,6 @@ namespace TrueCraft.Core.Logic.Blocks
public override byte Luminance { get { return 0; } } public override byte Luminance { get { return 0; } }
public override bool Opaque { get { return false; } }
public override string DisplayName { get { return "Grass"; } } public override string DisplayName { get { return "Grass"; } }
public override Tuple<int, int> GetTextureMap(byte metadata) public override Tuple<int, int> GetTextureMap(byte metadata)

View File

@ -4,6 +4,9 @@ using System.Linq;
using System.Text; using System.Text;
using TrueCraft.API.Logic; using TrueCraft.API.Logic;
using TrueCraft.API; using TrueCraft.API;
using TrueCraft.API.Entities;
using TrueCraft.API.World;
using TrueCraft.API.Networking;
namespace TrueCraft.Core.Logic namespace TrueCraft.Core.Logic
{ {
@ -14,5 +17,20 @@ namespace TrueCraft.Core.Logic
public virtual sbyte MaximumStack { get { return 64; } } public virtual sbyte MaximumStack { get { return 64; } }
public virtual string DisplayName { get { return string.Empty; } } 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
}
} }
} }

View File

@ -1,5 +1,9 @@
using System; using System;
using TrueCraft.API.Logic; 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 namespace TrueCraft.Core.Logic.Items
{ {
@ -12,5 +16,48 @@ namespace TrueCraft.Core.Logic.Items
public override sbyte MaximumStack { get { return 1; } } public override sbyte MaximumStack { get { return 1; } }
public override string DisplayName { get { return "Bed"; } } 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;
}
} }
} }

View File

@ -267,6 +267,7 @@
<Compile Include="Entities\LivingEntity.cs" /> <Compile Include="Entities\LivingEntity.cs" />
<Compile Include="Entities\ObjectEntity.cs" /> <Compile Include="Entities\ObjectEntity.cs" />
<Compile Include="Entities\PlayerEntity.cs" /> <Compile Include="Entities\PlayerEntity.cs" />
<Compile Include="Logic\Blocks\AirBlock.cs" />
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup> <ItemGroup>

View File

@ -5,6 +5,7 @@ using System.IO;
using System.Threading; using System.Threading;
using TrueCraft.API; using TrueCraft.API;
using TrueCraft.API.World; using TrueCraft.API.World;
using TrueCraft.API.Logic;
namespace TrueCraft.Core.World namespace TrueCraft.Core.World
{ {
@ -159,6 +160,18 @@ namespace TrueCraft.Core.World
return GetBlockDataFromChunk(adjustedCoordinates, chunk, coordinates); 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) private BlockDescriptor GetBlockDataFromChunk(Coordinates3D adjustedCoordinates, IChunk chunk, Coordinates3D coordinates)
{ {
return new BlockDescriptor return new BlockDescriptor

View File

@ -6,6 +6,7 @@ using TrueCraft.API;
using TrueCraft.API.World; using TrueCraft.API.World;
using TrueCraft.Core; using TrueCraft.Core;
using TrueCraft.Core.Windows; using TrueCraft.Core.Windows;
using TrueCraft.API.Logic;
namespace TrueCraft.Handlers namespace TrueCraft.Handlers
{ {
@ -43,7 +44,7 @@ namespace TrueCraft.Handlers
if (c.KnownEntities.Contains(client.Entity)) if (c.KnownEntities.Contains(client.Entity))
c.QueuePacket(new AnimationPacket(client.Entity.EntityID, AnimationPacket.PlayerAnimation.None)); 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); provider.BlockMined(descriptor, packet.Face, world, client);
break; break;
} }
@ -93,16 +94,17 @@ namespace TrueCraft.Handlers
{ {
if (use) if (use)
{ {
// Temporary: just place the damn thing var itemProvider = server.ItemRepository.GetItemProvider(slot.ID);
position += MathHelper.BlockFaceToCoordinates(packet.Face); if (itemProvider == null)
client.World.SetBlockID(position, (byte)slot.ID); {
client.World.SetMetadata(position, (byte)slot.Metadata); server.SendMessage(ChatColor.Red + "WARNING: item provider for ID {0} is null (player placing)", block.Value.ID);
slot.Count--; server.SendMessage(ChatColor.Red + "Error occured from client {0} at coordinates {1}", client.Username, block.Value.Coordinates);
client.Inventory[client.SelectedSlot] = slot; server.SendMessage(ChatColor.Red + "Packet logged at {0}, please report upstream", DateTime.Now);
// End temporary }
if (block != null) if (block != null)
{ {
// TODO: Use item on block if (itemProvider != null)
itemProvider.ItemUsedOnBlock(position, slot, packet.Face, client.World, client);
} }
else else
{ {

View File

@ -19,16 +19,11 @@ namespace TrueCraft
public IItemProvider GetItemProvider(short id) public IItemProvider GetItemProvider(short id)
{ {
int max = ItemProviders.Count - 1, min = 0; // TODO: Binary search
while (max >= min) for (int i = 0; i < ItemProviders.Count; i++)
{ {
int mid = (max - min / 2) + min; if (ItemProviders[i].ID == id)
if (ItemProviders[mid].ID == id) return ItemProviders[i];
return ItemProviders[mid];
else if(ItemProviders[mid].ID < id)
min = mid + 1;
else
max = min - 1;
} }
return null; return null;
} }

View File

@ -29,11 +29,35 @@ namespace TrueCraft
public IBlockRepository BlockRepository { get; private set; } public IBlockRepository BlockRepository { get; private set; }
public IItemRepository ItemRepository { get; private set; } public IItemRepository ItemRepository { get; private set; }
private bool _BlockUpdatesEnabled = true;
private struct BlockUpdate
{
public Coordinates3D Coordinates;
public IWorld World;
}
private Queue<BlockUpdate> PendingBlockUpdates { get; set; }
public bool BlockUpdatesEnabled
{
get
{
return _BlockUpdatesEnabled;
}
set
{
_BlockUpdatesEnabled = value;
if (_BlockUpdatesEnabled)
{
ProcessBlockUpdates();
}
}
}
private Timer EnvironmentWorker; private Timer EnvironmentWorker;
private Thread NetworkWorker; private Thread NetworkWorker;
private TcpListener Listener; private TcpListener Listener;
private readonly PacketHandler[] PacketHandlers; private readonly PacketHandler[] PacketHandlers;
private IList<ILogProvider> LogProviders; private IList<ILogProvider> LogProviders;
private object ClientLock = new object();
public MultiplayerServer() public MultiplayerServer()
{ {
@ -53,6 +77,7 @@ namespace TrueCraft
var itemRepository = new ItemRepository(); var itemRepository = new ItemRepository();
itemRepository.DiscoverItemProviders(); itemRepository.DiscoverItemProviders();
ItemRepository = itemRepository; ItemRepository = itemRepository;
PendingBlockUpdates = new Queue<BlockUpdate>();
reader.RegisterCorePackets(); reader.RegisterCorePackets();
Handlers.PacketHandlers.RegisterHandlers(this); Handlers.PacketHandlers.RegisterHandlers(this);
@ -93,6 +118,31 @@ namespace TrueCraft
(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);
}
}
} }
public void AddLogProvider(ILogProvider provider) public void AddLogProvider(ILogProvider provider)
@ -164,6 +214,7 @@ namespace TrueCraft
{ {
var tcpClient = Listener.EndAcceptTcpClient(result); var tcpClient = Listener.EndAcceptTcpClient(result);
var client = new RemoteClient(this, tcpClient.GetStream()); var client = new RemoteClient(this, tcpClient.GetStream());
lock (ClientLock)
Clients.Add(client); Clients.Add(client);
Listener.BeginAcceptTcpClient(AcceptClient, null); Listener.BeginAcceptTcpClient(AcceptClient, null);
} }
@ -184,11 +235,17 @@ namespace TrueCraft
bool idle = true; bool idle = true;
for (int i = 0; i < Clients.Count && i >= 0; i++) for (int i = 0; i < Clients.Count && i >= 0; i++)
{ {
Console.WriteLine("Running update " + DateTime.Now); RemoteClient client;
var client = Clients[i] as RemoteClient; lock (ClientLock)
var sendTimeout = DateTime.Now.AddMilliseconds(50); client = Clients[i] as RemoteClient;
while (client.PacketQueue.Count != 0 && DateTime.Now < sendTimeout) var sendTimeout = DateTime.Now.AddMilliseconds(100);
while (client.PacketQueue.Count != 0)
{ {
if (DateTime.Now > sendTimeout)
{
Console.WriteLine("Send timeout" + DateTime.Now);
break;
}
idle = false; idle = false;
try try
{ {
@ -225,9 +282,14 @@ namespace TrueCraft
Clients.RemoveAt(i); Clients.RemoveAt(i);
break; break;
} }
var receiveTimeout = DateTime.Now.AddMilliseconds(50); var receiveTimeout = DateTime.Now.AddMilliseconds(100);
while (client.DataAvailable && DateTime.Now < receiveTimeout) while (client.DataAvailable)
{ {
if (DateTime.Now > receiveTimeout)
{
Console.WriteLine("Receive timeout" + DateTime.Now);
break;
}
idle = false; idle = false;
var packet = PacketReader.ReadPacket(client.MinecraftStream); var packet = PacketReader.ReadPacket(client.MinecraftStream);
LogPacket(packet, true); LogPacket(packet, true);
@ -268,6 +330,7 @@ namespace TrueCraft
Thread.Sleep(100); Thread.Sleep(100);
if (client.Disconnected) if (client.Disconnected)
{ {
lock (ClientLock)
Clients.RemoveAt(i); Clients.RemoveAt(i);
break; break;
} }