mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Add script for excavating cubes (#1677)
* Add MineCube.cs * Clear unused comments and using directives * Move the command to a chatbot class * Set a maximum sleep time for block mining * Add tool selection function * Improve the block - tool detection * Improve naming and comments * Add missing blocktypes * Add block-tool assertion and tool switching in hotbar * Remove unused using declaratives and improve coordinate handling * Move Material2Tool in the Mapping folder * Add function to let the bot mine up to 5 blocks above its head * Remove obsolete function to detect breakability * Implement mineup command Users can dig out a 2 high square manually. The client will walk through it mining everything that is reachable above, while avoiding falling blocks and liquids. * Refactor big parts of the code Move the function for obtaining cubes to a seperate file. Sort Unbreakables alphabetically. Change the distance to wait in the mine function back to 2. * Fix suggestions from review Change several parts of the code according to the review Add credits * Convert the bot into a script file and move it to config folder Adjust the script to be loadable with /script Remove unnecessary code Add public modifier to material2tool * Add checking for lava and water for normal mining * Remove MineCube.cs from chatbots * Code re-format Rename variables Fix indentation Co-authored-by: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com>
This commit is contained in:
parent
349a3de8e4
commit
b3b9a26288
4 changed files with 1187 additions and 0 deletions
315
MinecraftClient/config/ChatBots/MineCube.cs
Normal file
315
MinecraftClient/config/ChatBots/MineCube.cs
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
//MCCScript 1.0
|
||||
|
||||
MCC.LoadBot(new MineCube());
|
||||
|
||||
//MCCScript Extensions
|
||||
|
||||
class MineCube : ChatBot
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
if (!GetTerrainEnabled())
|
||||
{
|
||||
LogToConsole(Translations.Get("extra.terrainandmovement_required"));
|
||||
UnloadBot();
|
||||
return;
|
||||
}
|
||||
RegisterChatBotCommand("mine", "Mine a cube from a to b", "/mine x y z OR /mine x1 y1 z1 x2 y2 z2", EvaluateMineCommand);
|
||||
RegisterChatBotCommand("mineup", "Walk over a flat cubic platform of blocks and mine everything above you", "/mine x1 y1 z1 x2 y2 z2 (y1 = y2)", EvaluateMineCommand);
|
||||
LogToConsole("Mining bot created by Daenges.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Dig out a 2 Block high cube and let the bot walk through it
|
||||
/// mining all blocks above it that it can reach.
|
||||
/// </summary>
|
||||
/// <param name="walkingArea">Area that the bot should walk through. (The lower Y coordinate of the 2 high cube.)</param>
|
||||
public void MineUp(Cube walkingArea)
|
||||
{
|
||||
foreach (Layer lay in walkingArea.LayersInCube)
|
||||
{
|
||||
foreach (Row r in lay.RowsInLayer)
|
||||
{
|
||||
foreach (Location loc in r.BlocksInRow)
|
||||
{
|
||||
Location currentLoc = GetCurrentLocation();
|
||||
|
||||
if (MoveToLocation(new Location(loc.X, loc.Y, loc.Z)))
|
||||
{
|
||||
while (Math.Round(GetCurrentLocation().Distance(loc)) > 1)
|
||||
{
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This block is not reachable for some reason.
|
||||
// Keep on going with the next collumn.
|
||||
LogDebugToConsole("Unable to walk to: " + loc.X.ToString() + " " + (loc.Y).ToString() + " " + loc.Z.ToString());
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int height = Convert.ToInt32(Math.Round(currentLoc.Y)) + 2; height < Convert.ToInt32(Math.Round(currentLoc.Y)) + 7; height++)
|
||||
{
|
||||
Location mineLocation = new Location(loc.X, height, loc.Z);
|
||||
Material mineLocationMaterial = GetWorld().GetBlock(mineLocation).Type;
|
||||
|
||||
// Stop mining process if breaking the next block could endager the bot
|
||||
// through falling blocks or liquids.
|
||||
if (IsGravityBlockAbove(mineLocation) || IsSorroundedByLiquid(mineLocation)) { break; }
|
||||
// Skip this block if it can not be mined.
|
||||
if (Material2Tool.IsUnbreakable(mineLocationMaterial)) { continue; }
|
||||
|
||||
//DateTime start = DateTime.Now;
|
||||
// Search this tool in hotbar and select the correct slot
|
||||
SelectCorrectSlotInHotbar(
|
||||
// Returns the correct tool for this type
|
||||
Material2Tool.GetCorrectToolForBlock(
|
||||
// returns the type of the current block
|
||||
mineLocationMaterial));
|
||||
|
||||
// Unable to check when breaking is over.
|
||||
if (DigBlock(mineLocation))
|
||||
{
|
||||
short i = 0; // Maximum wait time of 10 sec.
|
||||
while (GetWorld().GetBlock(mineLocation).Type != Material.Air && i <= 100)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebugToConsole("Unable to break this block: " + mineLocation.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogToConsole("Finished mining up.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Mines out a cube of blocks from top to bottom.
|
||||
/// </summary>
|
||||
/// <param name="cubeToMine">The cube that should be mined.</param>
|
||||
public void Mine(Cube cubeToMine)
|
||||
{
|
||||
foreach (Layer lay in cubeToMine.LayersInCube)
|
||||
{
|
||||
foreach (Row r in lay.RowsInLayer)
|
||||
{
|
||||
foreach (Location loc in r.BlocksInRow)
|
||||
{
|
||||
Material locMaterial = GetWorld().GetBlock(loc).Type;
|
||||
if (!Material2Tool.IsUnbreakable(locMaterial) && !IsSorroundedByLiquid(loc))
|
||||
{
|
||||
if (GetHeadLocation(GetCurrentLocation()).Distance(loc) > 5)
|
||||
{
|
||||
// Unable to detect when walking is over and goal is reached.
|
||||
if (MoveToLocation(new Location(loc.X, loc.Y + 1, loc.Z)))
|
||||
{
|
||||
while (GetCurrentLocation().Distance(loc) > 2)
|
||||
{
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebugToConsole("Unable to walk to: " + loc.X.ToString() + " " + (loc.Y + 1).ToString() + " " + loc.Z.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
//DateTime start = DateTime.Now;
|
||||
// Search this tool in hotbar and select the correct slot
|
||||
SelectCorrectSlotInHotbar(
|
||||
// Returns the correct tool for this type
|
||||
Material2Tool.GetCorrectToolForBlock(
|
||||
// returns the type of the current block
|
||||
GetWorld().GetBlock(loc).Type));
|
||||
|
||||
// Unable to check when breaking is over.
|
||||
if (DigBlock(loc))
|
||||
{
|
||||
short i = 0; // Maximum wait time of 10 sec.
|
||||
while (GetWorld().GetBlock(loc).Type != Material.Air && i <= 100)
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogDebugToConsole("Unable to break this block: " + loc.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LogToConsole("Mining finished.");
|
||||
}
|
||||
|
||||
public Func<Location, Location> GetHeadLocation = locFeet => new Location(locFeet.X, locFeet.Y + 1, locFeet.Z);
|
||||
|
||||
private void SelectCorrectSlotInHotbar(ItemType[] tools)
|
||||
{
|
||||
if (GetInventoryEnabled())
|
||||
{
|
||||
foreach (ItemType tool in tools)
|
||||
{
|
||||
int[] tempArray = GetPlayerInventory().SearchItem(tool);
|
||||
// Check whether an item could be found and make sure that it is in
|
||||
// a hotbar slot (36-44).
|
||||
if (tempArray.Length > 0 && tempArray[0] > 35)
|
||||
{
|
||||
// Changeslot takes numbers from 0-8
|
||||
ChangeSlot(Convert.ToInt16(tempArray[0] - 36));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LogToConsole("Activate Inventory Handling.");
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGravityBlockAbove(Location block)
|
||||
{
|
||||
World world = GetWorld();
|
||||
double blockX = Math.Round(block.X);
|
||||
double blockY = Math.Round(block.Y);
|
||||
double blockZ = Math.Round(block.Z);
|
||||
|
||||
List<Material> gravityBlockList = new List<Material>(new Material[] { Material.Gravel, Material.Sand, Material.RedSand, Material.Scaffolding, Material.Anvil, });
|
||||
|
||||
|
||||
var temptype = world.GetBlock(new Location(blockX, blockY + 1, blockZ)).Type;
|
||||
var tempLoc = gravityBlockList.Contains(world.GetBlock(new Location(blockX, blockY + 1, blockZ)).Type);
|
||||
|
||||
return
|
||||
// Block can not fall down on player e.g. Sand, Gravel etc.
|
||||
gravityBlockList.Contains(world.GetBlock(new Location(blockX, blockY + 1, blockZ)).Type);
|
||||
}
|
||||
|
||||
public bool IsSorroundedByLiquid(Location block)
|
||||
{
|
||||
World world = GetWorld();
|
||||
double blockX = Math.Round(block.X);
|
||||
double blockY = Math.Round(block.Y);
|
||||
double blockZ = Math.Round(block.Z);
|
||||
|
||||
List<Material> liquidBlockList = new List<Material>(new Material[] { Material.Water, Material.Lava, });
|
||||
|
||||
return // Liquid can not flow down the hole. Liquid is unable to flow diagonally.
|
||||
liquidBlockList.Contains(world.GetBlock(new Location(blockX, blockY + 1, blockZ)).Type) ||
|
||||
liquidBlockList.Contains(world.GetBlock(new Location(blockX - 1, blockY, blockZ)).Type) ||
|
||||
liquidBlockList.Contains(world.GetBlock(new Location(blockX + 1, blockY, blockZ)).Type) ||
|
||||
liquidBlockList.Contains(world.GetBlock(new Location(blockX, blockY, blockZ - 1)).Type) ||
|
||||
liquidBlockList.Contains(world.GetBlock(new Location(blockX, blockY, blockZ + 1)).Type);
|
||||
}
|
||||
|
||||
///
|
||||
private string getHelpPage()
|
||||
{
|
||||
return
|
||||
"Usage of the mine bot:\n" +
|
||||
"/mine <x1> <y1> <z1> <x2> <y2> <z2> OR /mine <x> <y> <z>\n" +
|
||||
"to excavate a cube of blocks from top to bottom. (2 high area above the cube must be dug free by hand.)\n" +
|
||||
"/mineup <x1> <y1> <z1> <x2> <y1> <z2> OR /mineup <x> <y> <z>\n" +
|
||||
"to walk over a quadratic field of blocks and simultaniously mine everything above the head. \n" +
|
||||
"(Mines up to 5 Blocks, stops if gravel or lava would fall. 2 High area below this must be dug fee by hand.)\n";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates the given command
|
||||
/// </summary>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="args"></param>
|
||||
/// <returns></returns>
|
||||
private string EvaluateMineCommand(string command, string[] args)
|
||||
{
|
||||
if (args.Length > 2)
|
||||
{
|
||||
Location startBlock;
|
||||
Location stopBlock;
|
||||
|
||||
if (args.Length > 5)
|
||||
{
|
||||
try
|
||||
{
|
||||
startBlock = new Location(
|
||||
double.Parse(args[0]),
|
||||
double.Parse(args[1]),
|
||||
double.Parse(args[2])
|
||||
);
|
||||
|
||||
stopBlock = new Location(
|
||||
double.Parse(args[3]),
|
||||
double.Parse(args[4]),
|
||||
double.Parse(args[5])
|
||||
);
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogDebugToConsole(e.ToString());
|
||||
return "Please enter correct coordinates as numbers.\n" + getHelpPage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Location tempLoc = GetCurrentLocation();
|
||||
startBlock = new Location(Math.Round(tempLoc.X),
|
||||
Math.Round(tempLoc.Y),
|
||||
Math.Round(tempLoc.Z));
|
||||
|
||||
try
|
||||
{
|
||||
stopBlock = new Location(
|
||||
double.Parse(args[0]),
|
||||
double.Parse(args[1]),
|
||||
double.Parse(args[2])
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogDebugToConsole(e.ToString());
|
||||
return "Please enter correct coordinates as numbers.\n" + getHelpPage();
|
||||
}
|
||||
}
|
||||
|
||||
if (command.Contains("mineup"))
|
||||
{
|
||||
if (Math.Round(startBlock.Y) != Math.Round(stopBlock.Y))
|
||||
{
|
||||
return "Both blocks must have the same Y value!\n" + getHelpPage();
|
||||
}
|
||||
|
||||
List<Material> materialWhitelist = new List<Material>() { Material.Air };
|
||||
Thread tempThread = new Thread(() => MineUp(CubeFromWorld.GetBlocksAsCube(GetWorld(), startBlock, stopBlock, materialWhitelist, isBlacklist: false)));
|
||||
tempThread.Start();
|
||||
return "Start mining up.";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Turn the cube around, so the bot always starts from the top.
|
||||
if (stopBlock.Y > startBlock.Y)
|
||||
{
|
||||
Location temp = stopBlock;
|
||||
stopBlock = startBlock;
|
||||
startBlock = temp;
|
||||
}
|
||||
|
||||
List<Material> blacklistedMaterials = new List<Material>() { Material.Air, Material.Water, Material.Lava };
|
||||
Thread tempThread = new Thread(() => Mine(CubeFromWorld.GetBlocksAsCube(GetWorld(), startBlock, stopBlock, blacklistedMaterials)));
|
||||
tempThread.Start();
|
||||
|
||||
return "Start mining cube.";
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid command syntax.\n" + getHelpPage();
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue