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>
/// Dig block
/// Attempt to dig a block at the specified location
/// </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="face">Block face</param>
protected void DigBlock(int status, Location location, Direction blockFace)
protected bool DigBlock(Location location)
{
Handler.DigBlock(status, location, blockFace);
return Handler.DigBlock(location);
}
/// <summary>
@ -977,9 +975,9 @@ namespace MinecraftClient
/// <param name="itemType">Item type</param>
/// <param name="count">Item count</param>
/// <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>

View file

@ -12,7 +12,9 @@ namespace MinecraftClient.Commands
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))
{
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>
/// <param name="ID">Item Type ID</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)
{
this.Type = (ItemType)id;

View file

@ -953,11 +953,11 @@ namespace MinecraftClient
/// <param name="slot">Destination inventory slot</param>
/// <param name="itemType">Item type</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>
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>
@ -1023,14 +1023,25 @@ namespace MinecraftClient
}
/// <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>
/// <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="blockFace">Block face (e.g. Direction.Up when digging from above)</param>
public bool DigBlock(int status, Location location, Direction blockFace)
public bool DigBlock(Location location)
{
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>
@ -1045,25 +1056,21 @@ namespace MinecraftClient
CurrentSlot = Convert.ToByte(slot);
return handler.SendHeldItemChange(slot);
}
else
{
return false;
}
else return false;
}
/// <summary>
/// Update sign text
/// </summary>
/// <param name="location"> sign location</param>
/// <param name="line1"> text one</param>
/// <param name="line2"> text two</param>
/// <param name="line3"> text three</param>
/// <param name="line4"> text1 four</param>
/// <param name="location">sign location</param>
/// <param name="line1">text one</param>
/// <param name="line2">text two</param>
/// <param name="line3">text three</param>
/// <param name="line4">text1 four</param>
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);
else { return false; }
}
#endregion

View file

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

View file

@ -27,7 +27,7 @@ namespace MinecraftClient
/// </remarks>
static class Program
{
private static McClient Client;
private static McClient client;
public static string[] startupargs;
public const string Version = MCHighestVersion;
@ -264,9 +264,9 @@ namespace MinecraftClient
//Start the main TCP client
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
if (Settings.ConsoleTitle != "")
@ -309,7 +309,7 @@ namespace MinecraftClient
{
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 (delaySeconds > 0)
{
@ -328,7 +328,7 @@ namespace MinecraftClient
{
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 (Settings.playerHeadAsIcon) { ConsoleIcon.revertToMCCIcon(); }
Environment.Exit(0);

View file

@ -336,8 +336,8 @@ namespace MinecraftClient.Protocol.Handlers
{
int itemID = ReadNextVarInt(cache);
byte itemCount = ReadNextByte(cache);
Dictionary<string, object> NBT = ReadNextNbt(cache);
return new Item(itemID, itemCount, NBT);
Dictionary<string, object> nbt = ReadNextNbt(cache);
return new Item(itemID, itemCount, nbt);
}
else return null;
}
@ -349,8 +349,8 @@ namespace MinecraftClient.Protocol.Handlers
return null;
byte itemCount = ReadNextByte(cache);
short itemDamage = ReadNextShort(cache);
Dictionary<string, object> NBT = ReadNextNbt(cache);
return new Item(itemID, itemCount, NBT);
Dictionary<string, object> nbt = ReadNextNbt(cache);
return new Item(itemID, itemCount, nbt);
}
}
@ -398,14 +398,14 @@ namespace MinecraftClient.Protocol.Handlers
/// </summary>
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 (cache.Peek() == 0) // TAG_End
{
cache.Dequeue();
return NbtData;
return nbtData;
}
if (cache.Peek() != 10) // 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
string rootName = Encoding.ASCII.GetString(ReadData(ReadNextUShort(cache), cache));
if (!String.IsNullOrEmpty(rootName))
NbtData[""] = rootName;
nbtData[""] = rootName;
}
while (true)
@ -422,14 +422,14 @@ namespace MinecraftClient.Protocol.Handlers
int fieldType = ReadNextByte(cache);
if (fieldType == 0) // TAG_End
return NbtData;
return nbtData;
int fieldNameLength = ReadNextUShort(cache);
string fieldName = Encoding.ASCII.GetString(ReadData(fieldNameLength, cache));
object fieldValue = ReadNbtField(cache, fieldType);
// 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
}
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
}

View file

@ -1500,13 +1500,13 @@ namespace MinecraftClient.Protocol.Handlers
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
{
List<byte> packet = new List<byte>();
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);
return true;
}
@ -1549,6 +1549,7 @@ namespace MinecraftClient.Protocol.Handlers
catch (System.IO.IOException) { return false; }
catch (ObjectDisposedException) { return false; }
}
public bool SendCloseWindow(int windowId)
{
try
@ -1565,10 +1566,20 @@ namespace MinecraftClient.Protocol.Handlers
catch (System.IO.IOException) { return false; }
catch (ObjectDisposedException) { return false; }
}
public bool SendUpdateSign(Location sign, string line1, string line2, string line3, string line4)
{
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>();
packet.AddRange(dataTypes.GetLocation(sign));
packet.AddRange(dataTypes.GetString(line1));

View file

@ -156,8 +156,9 @@ namespace MinecraftClient.Protocol
/// <param name="slot">Destination inventory slot</param>
/// <param name="itemType">Item type</param>
/// <param name="count">Item count</param>
/// <param name="nbt">Optional item NBT</param>
/// <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>
/// Plays animation
@ -183,7 +184,7 @@ namespace MinecraftClient.Protocol
bool SendPlayerBlockPlacement(int hand, Location location, Direction face);
/// <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>
/// <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>