Adjust dig block API

Attempt to automate dig start and dig complete (#1077)
This commit is contained in:
ORelio 2020-06-20 21:30:23 +02:00
parent 6df5076d19
commit 4cc29a6ee6
11 changed files with 113 additions and 48 deletions

View file

@ -745,14 +745,12 @@ namespace MinecraftClient
} }
/// <summary> /// <summary>
/// Dig block /// Attempt to dig a block at the specified location
/// </summary> /// </summary>
/// <param name="status">0 to start digging, 1 to cancel, 2 to finish ( https://wiki.vg/Protocol#Player_Digging )</param>
/// <param name="location">Location</param> /// <param name="location">Location</param>
/// <param name="face">Block face</param> protected bool DigBlock(Location location)
protected void DigBlock(int status, Location location, Direction blockFace)
{ {
Handler.DigBlock(status, location, blockFace); return Handler.DigBlock(location);
} }
/// <summary> /// <summary>
@ -977,9 +975,9 @@ namespace MinecraftClient
/// <param name="itemType">Item type</param> /// <param name="itemType">Item type</param>
/// <param name="count">Item count</param> /// <param name="count">Item count</param>
/// <returns>TRUE if item given successfully</returns> /// <returns>TRUE if item given successfully</returns>
protected bool CreativeGive(int slot, ItemType itemType, int count, Dictionary<string, object> NBT = null) protected bool CreativeGive(int slot, ItemType itemType, int count, Dictionary<string, object> nbt = null)
{ {
return Handler.DoCreativeGive(slot, itemType, count, NBT); return Handler.DoCreativeGive(slot, itemType, count, nbt);
} }
/// <summary> /// <summary>

View file

@ -12,7 +12,9 @@ namespace MinecraftClient.Commands
public override string Run(McClient handler, string command, Dictionary<string, object> localVars) public override string Run(McClient handler, string command, Dictionary<string, object> localVars)
{ {
if (!handler.GetInventoryEnabled()) return "Please enable InventoryHandling in the config file first."; if (!handler.GetTerrainEnabled())
return "Please enable InventoryHandling in the config file first.";
if (hasArg(command)) if (hasArg(command))
{ {
short slot; short slot;

View file

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MinecraftClient.Mapping;
namespace MinecraftClient.Commands
{
public class Dig : Command
{
public override string CMDName { get { return "dig"; } }
public override string CMDDesc { get { return "dig <x> <y> <z>: attempt to break a block"; } }
public override string Run(McClient handler, string command, Dictionary<string, object> localVars)
{
if (!handler.GetTerrainEnabled())
return "Please enable Terrain and Movements to use this command.";
if (hasArg(command))
{
string[] args = getArgs(command);
if (args.Length == 3)
{
try
{
int x = int.Parse(args[0]);
int y = int.Parse(args[1]);
int z = int.Parse(args[2]);
Location blockToBreak = new Location(x, y, z);
if (blockToBreak.DistanceSquared(handler.GetCurrentLocation()) >= 16)
return "You are too far away from this block.";
if (handler.GetWorld().GetBlock(blockToBreak).Type == Material.Air)
return "No block at this location (Air)";
if (handler.DigBlock(blockToBreak))
return String.Format("Attempting to dig block at {0} {1} {2}", x, y, z);
else return "Failed to start digging block.";
}
catch (FormatException) { return CMDDesc; }
}
else return CMDDesc;
}
else return CMDDesc;
}
}
}

View file

@ -30,7 +30,7 @@ namespace MinecraftClient.Inventory
/// </summary> /// </summary>
/// <param name="ID">Item Type ID</param> /// <param name="ID">Item Type ID</param>
/// <param name="Count">Item Count</param> /// <param name="Count">Item Count</param>
/// <param name="NBT">Item Metadata</param> /// <param name="nbt">Item Metadata</param>
public Item(int id, int count, Dictionary<string, object> nbt) public Item(int id, int count, Dictionary<string, object> nbt)
{ {
this.Type = (ItemType)id; this.Type = (ItemType)id;

View file

@ -953,11 +953,11 @@ namespace MinecraftClient
/// <param name="slot">Destination inventory slot</param> /// <param name="slot">Destination inventory slot</param>
/// <param name="itemType">Item type</param> /// <param name="itemType">Item type</param>
/// <param name="count">Item count</param> /// <param name="count">Item count</param>
/// <param name="NBT">Item NBT</param> /// <param name="nbt">Item NBT</param>
/// <returns>TRUE if item given successfully</returns> /// <returns>TRUE if item given successfully</returns>
public bool DoCreativeGive(int slot, ItemType itemType, int count, Dictionary<string, object> NBT = null) public bool DoCreativeGive(int slot, ItemType itemType, int count, Dictionary<string, object> nbt = null)
{ {
return handler.SendCreativeInventoryAction(slot, itemType, count, NBT); return handler.SendCreativeInventoryAction(slot, itemType, count, nbt);
} }
/// <summary> /// <summary>
@ -1023,14 +1023,25 @@ namespace MinecraftClient
} }
/// <summary> /// <summary>
/// Dig block. This method needs to be called at least twice: Once to begin digging, then a second time to finish digging /// Attempt to dig a block at the specified location
/// </summary> /// </summary>
/// <param name="status">0 to start digging, 1 to cancel, 2 to finish ( https://wiki.vg/Protocol#Player_Digging )</param>
/// <param name="location">Location of block to dig</param> /// <param name="location">Location of block to dig</param>
/// <param name="blockFace">Block face (e.g. Direction.Up when digging from above)</param> public bool DigBlock(Location location)
public bool DigBlock(int status, Location location, Direction blockFace)
{ {
return handler.SendPlayerDigging(status, location, blockFace); if (GetTerrainEnabled())
{
// TODO select best face from current player location
Direction blockFace = Direction.Down;
// Look at block before attempting to break it
UpdateLocation(GetCurrentLocation(), location);
// Send dig start and dig end, will need to wait for server response to know dig result
// See https://wiki.vg/How_to_Write_a_Client#Digging for more details
return handler.SendPlayerDigging(0, location, blockFace)
&& handler.SendPlayerDigging(2, location, blockFace);
}
else return false;
} }
/// <summary> /// <summary>
@ -1045,25 +1056,21 @@ namespace MinecraftClient
CurrentSlot = Convert.ToByte(slot); CurrentSlot = Convert.ToByte(slot);
return handler.SendHeldItemChange(slot); return handler.SendHeldItemChange(slot);
} }
else else return false;
{
return false;
}
} }
/// <summary> /// <summary>
/// Update sign text /// Update sign text
/// </summary> /// </summary>
/// <param name="location"> sign location</param> /// <param name="location">sign location</param>
/// <param name="line1"> text one</param> /// <param name="line1">text one</param>
/// <param name="line2"> text two</param> /// <param name="line2">text two</param>
/// <param name="line3"> text three</param> /// <param name="line3">text three</param>
/// <param name="line4"> text1 four</param> /// <param name="line4">text1 four</param>
public bool UpdateSign(Location location, string line1, string line2, string line3, string line4) public bool UpdateSign(Location location, string line1, string line2, string line3, string line4)
{ {
if (line1.Length <= 23 & line2.Length <= 23 & line3.Length <= 23 & line4.Length <= 23) // TODO Open sign editor first https://wiki.vg/Protocol#Open_Sign_Editor
return handler.SendUpdateSign(location, line1, line2, line3, line4); return handler.SendUpdateSign(location, line1, line2, line3, line4);
else { return false; }
} }
#endregion #endregion

View file

@ -93,6 +93,7 @@
<Compile Include="Commands\ChangeSlot.cs" /> <Compile Include="Commands\ChangeSlot.cs" />
<Compile Include="Commands\Connect.cs" /> <Compile Include="Commands\Connect.cs" />
<Compile Include="Commands\Debug.cs" /> <Compile Include="Commands\Debug.cs" />
<Compile Include="Commands\Dig.cs" />
<Compile Include="Commands\Inventory.cs" /> <Compile Include="Commands\Inventory.cs" />
<Compile Include="Commands\Look.cs" /> <Compile Include="Commands\Look.cs" />
<Compile Include="Commands\Move.cs" /> <Compile Include="Commands\Move.cs" />

View file

@ -27,7 +27,7 @@ namespace MinecraftClient
/// </remarks> /// </remarks>
static class Program static class Program
{ {
private static McClient Client; private static McClient client;
public static string[] startupargs; public static string[] startupargs;
public const string Version = MCHighestVersion; public const string Version = MCHighestVersion;
@ -264,9 +264,9 @@ namespace MinecraftClient
//Start the main TCP client //Start the main TCP client
if (Settings.SingleCommand != "") if (Settings.SingleCommand != "")
{ {
Client = new McClient(session.PlayerName, session.PlayerID, session.ID, Settings.ServerIP, Settings.ServerPort, protocolversion, forgeInfo, Settings.SingleCommand); client = new McClient(session.PlayerName, session.PlayerID, session.ID, Settings.ServerIP, Settings.ServerPort, protocolversion, forgeInfo, Settings.SingleCommand);
} }
else Client = new McClient(session.PlayerName, session.PlayerID, session.ID, protocolversion, forgeInfo, Settings.ServerIP, Settings.ServerPort); else client = new McClient(session.PlayerName, session.PlayerID, session.ID, protocolversion, forgeInfo, Settings.ServerIP, Settings.ServerPort);
//Update console title //Update console title
if (Settings.ConsoleTitle != "") if (Settings.ConsoleTitle != "")
@ -309,7 +309,7 @@ namespace MinecraftClient
{ {
new Thread(new ThreadStart(delegate new Thread(new ThreadStart(delegate
{ {
if (Client != null) { Client.Disconnect(); ConsoleIO.Reset(); } if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
if (offlinePrompt != null) { offlinePrompt.Abort(); offlinePrompt = null; ConsoleIO.Reset(); } if (offlinePrompt != null) { offlinePrompt.Abort(); offlinePrompt = null; ConsoleIO.Reset(); }
if (delaySeconds > 0) if (delaySeconds > 0)
{ {
@ -328,7 +328,7 @@ namespace MinecraftClient
{ {
new Thread(new ThreadStart(delegate new Thread(new ThreadStart(delegate
{ {
if (Client != null) { Client.Disconnect(); ConsoleIO.Reset(); } if (client != null) { client.Disconnect(); ConsoleIO.Reset(); }
if (offlinePrompt != null) { offlinePrompt.Abort(); offlinePrompt = null; ConsoleIO.Reset(); } if (offlinePrompt != null) { offlinePrompt.Abort(); offlinePrompt = null; ConsoleIO.Reset(); }
if (Settings.playerHeadAsIcon) { ConsoleIcon.revertToMCCIcon(); } if (Settings.playerHeadAsIcon) { ConsoleIcon.revertToMCCIcon(); }
Environment.Exit(0); Environment.Exit(0);

View file

@ -336,8 +336,8 @@ namespace MinecraftClient.Protocol.Handlers
{ {
int itemID = ReadNextVarInt(cache); int itemID = ReadNextVarInt(cache);
byte itemCount = ReadNextByte(cache); byte itemCount = ReadNextByte(cache);
Dictionary<string, object> NBT = ReadNextNbt(cache); Dictionary<string, object> nbt = ReadNextNbt(cache);
return new Item(itemID, itemCount, NBT); return new Item(itemID, itemCount, nbt);
} }
else return null; else return null;
} }
@ -349,8 +349,8 @@ namespace MinecraftClient.Protocol.Handlers
return null; return null;
byte itemCount = ReadNextByte(cache); byte itemCount = ReadNextByte(cache);
short itemDamage = ReadNextShort(cache); short itemDamage = ReadNextShort(cache);
Dictionary<string, object> NBT = ReadNextNbt(cache); Dictionary<string, object> nbt = ReadNextNbt(cache);
return new Item(itemID, itemCount, NBT); return new Item(itemID, itemCount, nbt);
} }
} }
@ -398,14 +398,14 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary> /// </summary>
private Dictionary<string, object> ReadNextNbt(Queue<byte> cache, bool root) private Dictionary<string, object> ReadNextNbt(Queue<byte> cache, bool root)
{ {
Dictionary<string, object> NbtData = new Dictionary<string, object>(); Dictionary<string, object> nbtData = new Dictionary<string, object>();
if (root) if (root)
{ {
if (cache.Peek() == 0) // TAG_End if (cache.Peek() == 0) // TAG_End
{ {
cache.Dequeue(); cache.Dequeue();
return NbtData; return nbtData;
} }
if (cache.Peek() != 10) // TAG_Compound if (cache.Peek() != 10) // TAG_Compound
throw new System.IO.InvalidDataException("Failed to decode NBT: Does not start with TAG_Compound"); throw new System.IO.InvalidDataException("Failed to decode NBT: Does not start with TAG_Compound");
@ -414,7 +414,7 @@ namespace MinecraftClient.Protocol.Handlers
// NBT root name // NBT root name
string rootName = Encoding.ASCII.GetString(ReadData(ReadNextUShort(cache), cache)); string rootName = Encoding.ASCII.GetString(ReadData(ReadNextUShort(cache), cache));
if (!String.IsNullOrEmpty(rootName)) if (!String.IsNullOrEmpty(rootName))
NbtData[""] = rootName; nbtData[""] = rootName;
} }
while (true) while (true)
@ -422,14 +422,14 @@ namespace MinecraftClient.Protocol.Handlers
int fieldType = ReadNextByte(cache); int fieldType = ReadNextByte(cache);
if (fieldType == 0) // TAG_End if (fieldType == 0) // TAG_End
return NbtData; return nbtData;
int fieldNameLength = ReadNextUShort(cache); int fieldNameLength = ReadNextUShort(cache);
string fieldName = Encoding.ASCII.GetString(ReadData(fieldNameLength, cache)); string fieldName = Encoding.ASCII.GetString(ReadData(fieldNameLength, cache));
object fieldValue = ReadNbtField(cache, fieldType); object fieldValue = ReadNbtField(cache, fieldType);
// This will override previous tags with the same name // This will override previous tags with the same name
NbtData[fieldName] = fieldValue; nbtData[fieldName] = fieldValue;
} }
} }

View file

@ -703,7 +703,7 @@ namespace MinecraftClient.Protocol.Handlers
return false; //Currently not implemented return false; //Currently not implemented
} }
public bool SendCreativeInventoryAction(int slot, ItemType item, int count, Dictionary<string, object> NBT) public bool SendCreativeInventoryAction(int slot, ItemType item, int count, Dictionary<string, object> nbt)
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }

View file

@ -1500,13 +1500,13 @@ namespace MinecraftClient.Protocol.Handlers
catch (ObjectDisposedException) { return false; } catch (ObjectDisposedException) { return false; }
} }
public bool SendCreativeInventoryAction(int slot, ItemType itemType, int count, Dictionary<string, object> NBT) public bool SendCreativeInventoryAction(int slot, ItemType itemType, int count, Dictionary<string, object> nbt)
{ {
try try
{ {
List<byte> packet = new List<byte>(); List<byte> packet = new List<byte>();
packet.AddRange(dataTypes.GetShort((short)slot)); packet.AddRange(dataTypes.GetShort((short)slot));
packet.AddRange(dataTypes.GetItemSlot(new Item((int)itemType, count, NBT))); packet.AddRange(dataTypes.GetItemSlot(new Item((int)itemType, count, nbt)));
SendPacket(PacketOutgoingType.CreativeInventoryAction, packet); SendPacket(PacketOutgoingType.CreativeInventoryAction, packet);
return true; return true;
} }
@ -1549,6 +1549,7 @@ namespace MinecraftClient.Protocol.Handlers
catch (System.IO.IOException) { return false; } catch (System.IO.IOException) { return false; }
catch (ObjectDisposedException) { return false; } catch (ObjectDisposedException) { return false; }
} }
public bool SendCloseWindow(int windowId) public bool SendCloseWindow(int windowId)
{ {
try try
@ -1565,10 +1566,20 @@ namespace MinecraftClient.Protocol.Handlers
catch (System.IO.IOException) { return false; } catch (System.IO.IOException) { return false; }
catch (ObjectDisposedException) { return false; } catch (ObjectDisposedException) { return false; }
} }
public bool SendUpdateSign(Location sign, string line1, string line2, string line3, string line4) public bool SendUpdateSign(Location sign, string line1, string line2, string line3, string line4)
{ {
try try
{ {
if (line1.Length > 23)
line1 = line1.Substring(0, 23);
if (line2.Length > 23)
line2 = line1.Substring(0, 23);
if (line3.Length > 23)
line3 = line1.Substring(0, 23);
if (line4.Length > 23)
line4 = line1.Substring(0, 23);
List<byte> packet = new List<byte>(); List<byte> packet = new List<byte>();
packet.AddRange(dataTypes.GetLocation(sign)); packet.AddRange(dataTypes.GetLocation(sign));
packet.AddRange(dataTypes.GetString(line1)); packet.AddRange(dataTypes.GetString(line1));

View file

@ -156,8 +156,9 @@ namespace MinecraftClient.Protocol
/// <param name="slot">Destination inventory slot</param> /// <param name="slot">Destination inventory slot</param>
/// <param name="itemType">Item type</param> /// <param name="itemType">Item type</param>
/// <param name="count">Item count</param> /// <param name="count">Item count</param>
/// <param name="nbt">Optional item NBT</param>
/// <returns>TRUE if item given successfully</returns> /// <returns>TRUE if item given successfully</returns>
bool SendCreativeInventoryAction(int slot, ItemType itemType, int count, Dictionary<string, object> NBT); bool SendCreativeInventoryAction(int slot, ItemType itemType, int count, Dictionary<string, object> nbt);
/// <summary> /// <summary>
/// Plays animation /// Plays animation
@ -183,7 +184,7 @@ namespace MinecraftClient.Protocol
bool SendPlayerBlockPlacement(int hand, Location location, Direction face); bool SendPlayerBlockPlacement(int hand, Location location, Direction face);
/// <summary> /// <summary>
/// Send player blog digging packet to the server /// Send player blog digging packet to the server. This packet needs to be called at least twice: Once to begin digging, then a second time to finish digging
/// </summary> /// </summary>
/// <param name="status">0 to start digging, 1 to cancel, 2 to finish ( https://wiki.vg/Protocol#Player_Digging )</param> /// <param name="status">0 to start digging, 1 to cancel, 2 to finish ( https://wiki.vg/Protocol#Player_Digging )</param>
/// <param name="location">Location</param> /// <param name="location">Location</param>