Enforce digging time and damage items when used

Closes #11

Partially addresses #12
This commit is contained in:
Drew DeVault 2015-07-01 15:22:27 -06:00
parent a77822950b
commit fa8c4a6877
10 changed files with 216 additions and 13 deletions

View File

@ -8,27 +8,86 @@ namespace TrueCraft.API.Networking
{
public interface IRemoteClient
{
/// <summary>
/// Minecraft stream used to communicate with this client.
/// </summary>
IMinecraftStream MinecraftStream { get; }
/// <summary>
/// Returns true if this client has data pending in the network stream.
/// </summary>
bool DataAvailable { get; }
/// <summary>
/// The world this client is present in.
/// </summary>
IWorld World { get; }
/// <summary>
/// The entity associated with this client.
/// </summary>
IEntity Entity { get; }
/// <summary>
/// This client's inventory.
/// </summary>
IWindow Inventory { get; }
/// <summary>
/// The username of the connected client. May be null if not yet ascertained.
/// </summary>
string Username { get; }
/// <summary>
/// The slot index this user has selected in their hotbar.
/// </summary>
short SelectedSlot { get; }
/// <summary>
/// The item stack at the slot the user has selected in their hotbar.
/// </summary>
ItemStack SelectedItem { get; }
/// <summary>
/// The server this user is playing on.
/// </summary>
IMultiplayerServer Server { get; }
/// <summary>
/// If true, this client will be sent logging information as chat messages.
/// </summary>
bool EnableLogging { get; set; }
/// <summary>
/// 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.
/// </summary>
DateTime ExpectedDigComplete { get; set; }
/// <summary>
/// True if this client has been disconnected. You should cease sending packets and
/// so on, this client is just waiting to be reaped.
/// </summary>
bool Disconnected { get; }
/// <summary>
/// Loads player data from disk for this client.
/// </summary>
bool Load();
/// <summary>
/// Saves player data to disk for this client.
/// </summary>
void Save();
/// <summary>
/// Queues a packet to be sent to this client.
/// </summary>
void QueuePacket(IPacket packet);
/// <summary>
/// Disconnects this client from the server.
/// </summary>
void Disconnect();
/// <summary>
/// Sends a chat message to this client.
/// </summary>
void SendMessage(string message);
/// <summary>
/// If logging is enabled, sends your message to the client as chat.
/// </summary>
void Log(string message, params object[] parameters);
/// <summary>
/// Opens a window on the client. This sends the appropriate packets and tracks
/// this window as the currently open window.
/// </summary>
void OpenWindow(IWindow window);
}
}

View File

@ -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);
}
}
/// <summary>
/// Gets the time required to mine the given block with the given item.
/// </summary>
/// <returns>The harvest time in milliseconds.</returns>
/// <param name="blockId">Block identifier.</param>
/// <param name="itemId">Item identifier.</param>
/// <param name="damage">Damage sustained by the item.</param>
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);
}
}
}

View File

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

View File

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

View File

@ -36,7 +36,7 @@
<HintPath>..\lib\Ionic.Zip.Reduced.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages>

View File

@ -34,12 +34,12 @@
<Reference Include="Xwt">
<HintPath>..\lib\Xwt.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.6.0.8\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Ionic.Zip.Reduced">
<HintPath>..\lib\Ionic.Zip.Reduced.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json">
<HintPath>..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Program.cs" />
@ -96,10 +96,10 @@
<None Include="Xwt.WPF.dll">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
<None Include="truecraft">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Content\truecraft-logo.png" />

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Newtonsoft.Json" version="6.0.8" targetFramework="net45" />
<package id="Newtonsoft.Json" version="7.0.1" targetFramework="net45" />
</packages>

View File

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

View File

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