diff --git a/TrueCraft.API/Networking/IRemoteClient.cs b/TrueCraft.API/Networking/IRemoteClient.cs
index 3e66928..bbd1f5e 100644
--- a/TrueCraft.API/Networking/IRemoteClient.cs
+++ b/TrueCraft.API/Networking/IRemoteClient.cs
@@ -8,27 +8,86 @@ namespace TrueCraft.API.Networking
{
public interface IRemoteClient
{
+ ///
+ /// Minecraft stream used to communicate with this client.
+ ///
IMinecraftStream MinecraftStream { get; }
+ ///
+ /// Returns true if this client has data pending in the network stream.
+ ///
bool DataAvailable { get; }
+ ///
+ /// The world this client is present in.
+ ///
IWorld World { get; }
+ ///
+ /// The entity associated with this client.
+ ///
IEntity Entity { get; }
+ ///
+ /// This client's inventory.
+ ///
IWindow Inventory { get; }
+ ///
+ /// The username of the connected client. May be null if not yet ascertained.
+ ///
string Username { get; }
+ ///
+ /// The slot index this user has selected in their hotbar.
+ ///
short SelectedSlot { get; }
+ ///
+ /// The item stack at the slot the user has selected in their hotbar.
+ ///
ItemStack SelectedItem { get; }
+ ///
+ /// The server this user is playing on.
+ ///
IMultiplayerServer Server { get; }
+ ///
+ /// If true, this client will be sent logging information as chat messages.
+ ///
bool EnableLogging { get; set; }
-
+ ///
+ /// The time the user is expected to complete the active digging operation,
+ /// depending on what kind of block they are mining and what tool they're using
+ /// to do it with.
+ ///
+ DateTime ExpectedDigComplete { get; set; }
+ ///
+ /// True if this client has been disconnected. You should cease sending packets and
+ /// so on, this client is just waiting to be reaped.
+ ///
bool Disconnected { get; }
+ ///
+ /// Loads player data from disk for this client.
+ ///
bool Load();
+ ///
+ /// Saves player data to disk for this client.
+ ///
void Save();
+ ///
+ /// Queues a packet to be sent to this client.
+ ///
void QueuePacket(IPacket packet);
-
+ ///
+ /// Disconnects this client from the server.
+ ///
void Disconnect();
-
+ ///
+ /// Sends a chat message to this client.
+ ///
void SendMessage(string message);
+ ///
+ /// If logging is enabled, sends your message to the client as chat.
+ ///
void Log(string message, params object[] parameters);
+ ///
+ /// Opens a window on the client. This sends the appropriate packets and tracks
+ /// this window as the currently open window.
+ ///
void OpenWindow(IWindow window);
}
}
\ No newline at end of file
diff --git a/TrueCraft.Core/Logic/BlockProvider.cs b/TrueCraft.Core/Logic/BlockProvider.cs
index 7900713..b0f8fd9 100644
--- a/TrueCraft.Core/Logic/BlockProvider.cs
+++ b/TrueCraft.Core/Logic/BlockProvider.cs
@@ -9,6 +9,7 @@ using TrueCraft.API.Server;
using TrueCraft.Core.Logic.Blocks;
using System.Linq;
using fNbt;
+using TrueCraft.Core.Logic.Items;
namespace TrueCraft.Core.Logic
{
@@ -242,5 +243,91 @@ namespace TrueCraft.Core.Logic
return new BoundingBox(Vector3.Zero, Vector3.One);
}
}
+
+ ///
+ /// Gets the time required to mine the given block with the given item.
+ ///
+ /// The harvest time in milliseconds.
+ /// Block identifier.
+ /// Item identifier.
+ /// Damage sustained by the item.
+ public static int GetHarvestTime(byte blockId, short itemId, out short damage)
+ {
+ // Reference:
+ // http://minecraft.gamepedia.com/index.php?title=Breaking&oldid=138286
+
+ damage = 0;
+
+ var block = BlockRepository.GetBlockProvider(blockId);
+ var item = ItemRepository.GetItemProvider(itemId);
+
+ double hardness = block.Hardness;
+ if (hardness == -1)
+ return -1;
+
+ double time = hardness * 1.5;
+
+ var tool = ToolType.None;
+ var material = ToolMaterial.None;
+
+ if (item is ToolItem)
+ {
+ var _ = item as ToolItem;
+ tool = _.ToolType;
+ material = _.Material;
+
+ if ((block.EffectiveTools & tool) == 0 || (block.EffectiveToolMaterials & material) == 0)
+ {
+ time *= 3.33; // Add time for ineffective tools
+ }
+ if (material != ToolMaterial.None)
+ {
+ switch (material)
+ {
+ case ToolMaterial.Wood:
+ time /= 2;
+ break;
+ case ToolMaterial.Stone:
+ time /= 4;
+ break;
+ case ToolMaterial.Iron:
+ time /= 6;
+ break;
+ case ToolMaterial.Diamond:
+ time /= 8;
+ break;
+ case ToolMaterial.Gold:
+ time /= 12;
+ break;
+ }
+ }
+ damage = 1;
+ if (tool == ToolType.Shovel || tool == ToolType.Axe || tool == ToolType.Pickaxe)
+ {
+ damage = (short)(hardness != 0 ? 1 : 0);
+ }
+ else if (tool == ToolType.Sword)
+ {
+ damage = (short)(hardness != 0 ? 2 : 0);
+ time /= 1.5;
+ if (block is CobwebBlock)
+ time /= 1.5;
+ }
+ else if (tool == ToolType.Hoe)
+ damage = 0; // What? This doesn't seem right
+ else if (item is ShearsItem)
+ {
+ if (block is WoolBlock)
+ time /= 5;
+ else if (block is LeavesBlock || block is CobwebBlock)
+ time /= 15;
+ if (block is LeavesBlock || block is CobwebBlock || block is TallGrassBlock)
+ damage = 1;
+ else
+ damage = 0;
+ }
+ }
+ return (int)(time * 1000);
+ }
}
}
\ No newline at end of file
diff --git a/TrueCraft.Core/Logic/Blocks/TallGrassBlock.cs b/TrueCraft.Core/Logic/Blocks/TallGrassBlock.cs
index 3597095..ddc66e2 100644
--- a/TrueCraft.Core/Logic/Blocks/TallGrassBlock.cs
+++ b/TrueCraft.Core/Logic/Blocks/TallGrassBlock.cs
@@ -30,6 +30,11 @@ namespace TrueCraft.Core.Logic.Blocks
public override BoundingBox? BoundingBox { get { return null; } }
+ public override Coordinates3D GetSupportDirection(BlockDescriptor descriptor)
+ {
+ return Coordinates3D.Down;
+ }
+
public override Tuple GetTextureMap(byte metadata)
{
return new Tuple(7, 2);
diff --git a/TrueCraft.Core/Logic/Items/ToolItem.cs b/TrueCraft.Core/Logic/Items/ToolItem.cs
index f7b9b0a..22aed23 100644
--- a/TrueCraft.Core/Logic/Items/ToolItem.cs
+++ b/TrueCraft.Core/Logic/Items/ToolItem.cs
@@ -15,5 +15,27 @@ namespace TrueCraft.Core.Logic
public virtual short BaseDurability { get { return 0; } }
public override sbyte MaximumStack { get { return 1; } }
+
+ public virtual int Uses
+ {
+ get
+ {
+ switch (Material)
+ {
+ case ToolMaterial.Gold:
+ return 33;
+ case ToolMaterial.Wood:
+ return 60;
+ case ToolMaterial.Stone:
+ return 132;
+ case ToolMaterial.Iron:
+ return 251;
+ case ToolMaterial.Diamond:
+ return 1562;
+ default:
+ return -1;
+ }
+ }
+ }
}
}
\ No newline at end of file
diff --git a/TrueCraft.Core/TrueCraft.Core.csproj b/TrueCraft.Core/TrueCraft.Core.csproj
index 672b76c..0dc194a 100644
--- a/TrueCraft.Core/TrueCraft.Core.csproj
+++ b/TrueCraft.Core/TrueCraft.Core.csproj
@@ -36,7 +36,7 @@
..\lib\Ionic.Zip.Reduced.dll
- ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll
+ ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
diff --git a/TrueCraft.Core/packages.config b/TrueCraft.Core/packages.config
index 27ac881..284ec0a 100644
--- a/TrueCraft.Core/packages.config
+++ b/TrueCraft.Core/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/TrueCraft.Launcher/TrueCraft.Launcher.csproj b/TrueCraft.Launcher/TrueCraft.Launcher.csproj
index a1c8fc9..8f1eb47 100644
--- a/TrueCraft.Launcher/TrueCraft.Launcher.csproj
+++ b/TrueCraft.Launcher/TrueCraft.Launcher.csproj
@@ -34,12 +34,12 @@
..\lib\Xwt.dll
-
- ..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll
-
..\lib\Ionic.Zip.Reduced.dll
+
+ ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
+
@@ -96,10 +96,10 @@
PreserveNewest
-
PreserveNewest
+
diff --git a/TrueCraft.Launcher/packages.config b/TrueCraft.Launcher/packages.config
index 27ac881..284ec0a 100644
--- a/TrueCraft.Launcher/packages.config
+++ b/TrueCraft.Launcher/packages.config
@@ -1,4 +1,4 @@
-
+
\ No newline at end of file
diff --git a/TrueCraft/Handlers/InteractionHandlers.cs b/TrueCraft/Handlers/InteractionHandlers.cs
index 17f955c..d972741 100644
--- a/TrueCraft/Handlers/InteractionHandlers.cs
+++ b/TrueCraft/Handlers/InteractionHandlers.cs
@@ -12,6 +12,7 @@ using fNbt;
using TrueCraft.Core.Logic.Blocks;
using System.Linq;
using TrueCraft.Core.Logic.Items;
+using TrueCraft.Core.Logic;
namespace TrueCraft.Handlers
{
@@ -25,6 +26,8 @@ namespace TrueCraft.Handlers
var position = new Coordinates3D(packet.X, packet.Y, packet.Z);
var descriptor = world.GetBlockData(position);
var provider = server.BlockRepository.GetBlockProvider(descriptor.ID);
+ short damage;
+ int time;
switch (packet.PlayerAction)
{
case PlayerDiggingPacket.Action.DropItem:
@@ -64,9 +67,13 @@ namespace TrueCraft.Handlers
// So if you want to blame anyone, send flames to Notch for the stupid idea of not sending "stop digging" packets
// for hardness == 0 blocks.
- if (provider != null && provider.Hardness == 0
- || (client.SelectedItem.ID == ShearsItem.ItemID && provider is LeavesBlock))
+ time = BlockProvider.GetHarvestTime(descriptor.ID, client.SelectedItem.ID, out damage);
+ if (time <= 20)
+ {
provider.BlockMined(descriptor, packet.Face, world, client);
+ break;
+ }
+ client.ExpectedDigComplete = DateTime.UtcNow.AddMilliseconds(time);
break;
case PlayerDiggingPacket.Action.StopDigging:
foreach (var nearbyClient in server.Clients)
@@ -76,7 +83,29 @@ namespace TrueCraft.Handlers
c.QueuePacket(new AnimationPacket(client.Entity.EntityID, AnimationPacket.PlayerAnimation.None));
}
if (provider != null && descriptor.ID != 0)
- provider.BlockMined(descriptor, packet.Face, world, client);
+ {
+ time = BlockProvider.GetHarvestTime(descriptor.ID, client.SelectedItem.ID, out damage);
+ if (time <= 20)
+ break; // Already handled earlier
+ var diff = (DateTime.UtcNow - client.ExpectedDigComplete).TotalMilliseconds;
+ if (diff > -100) // Allow a small tolerance
+ {
+ provider.BlockMined(descriptor, packet.Face, world, client);
+ // Damage the item
+ if (damage != 0)
+ {
+ var tool = server.ItemRepository.GetItemProvider(client.SelectedItem.ID) as ToolItem;
+ if (tool != null && tool.Uses != -1)
+ {
+ var slot = client.SelectedItem;
+ slot.Metadata += damage;
+ if (slot.Metadata >= tool.Uses)
+ slot.Count = 0; // Destroy item
+ client.Inventory[client.SelectedSlot] = slot;
+ }
+ }
+ }
+ }
break;
}
}
diff --git a/TrueCraft/RemoteClient.cs b/TrueCraft/RemoteClient.cs
index e467800..15970aa 100644
--- a/TrueCraft/RemoteClient.cs
+++ b/TrueCraft/RemoteClient.cs
@@ -70,6 +70,7 @@ namespace TrueCraft
public IWindow CurrentWindow { get; internal set; }
public bool EnableLogging { get; set; }
public IPacket LastSuccessfulPacket { get; set; }
+ public DateTime ExpectedDigComplete { get; set; }
public Socket Connection { get; private set; }