2020-07-07 11:38:15 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Text;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
using System.IO;
|
2020-07-07 11:38:15 +08:00
|
|
|
|
using MinecraftClient.Inventory;
|
2020-07-09 14:30:24 +08:00
|
|
|
|
using MinecraftClient.Mapping;
|
2020-07-07 11:38:15 +08:00
|
|
|
|
|
|
|
|
|
|
namespace MinecraftClient.ChatBots
|
|
|
|
|
|
{
|
2020-07-23 20:32:02 +08:00
|
|
|
|
class AutoCraft : ChatBot
|
2020-07-07 11:38:15 +08:00
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private bool waitingForMaterials = false;
|
2020-07-09 22:21:39 +08:00
|
|
|
|
private bool waitingForUpdate = false;
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private bool waitingForTable = false;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
private bool craftingFailed = false;
|
2020-07-09 22:21:39 +08:00
|
|
|
|
private int inventoryInUse = -2;
|
|
|
|
|
|
private int index = 0;
|
|
|
|
|
|
private Recipe recipeInUse;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
private List<ActionStep> actionSteps = new List<ActionStep>();
|
2020-07-09 22:21:39 +08:00
|
|
|
|
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private Location tableLocation = new Location();
|
|
|
|
|
|
private bool abortOnFailure = true;
|
|
|
|
|
|
private int updateDebounceValue = 2;
|
2020-07-09 22:21:39 +08:00
|
|
|
|
private int updateDebounce = 0;
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private int updateTimeoutValue = 10;
|
|
|
|
|
|
private int updateTimeout = 0;
|
|
|
|
|
|
private string timeoutAction = "unspecified";
|
2020-07-09 22:21:39 +08:00
|
|
|
|
|
2020-07-19 21:27:01 +08:00
|
|
|
|
private string configPath = @"autocraft\config.ini";
|
2020-08-11 15:34:07 +08:00
|
|
|
|
private string lastRecipe = ""; // Used in parsing recipe config
|
2020-07-07 11:38:15 +08:00
|
|
|
|
|
2020-07-19 21:27:01 +08:00
|
|
|
|
private Dictionary<string, Recipe> recipes = new Dictionary<string, Recipe>();
|
2020-07-12 19:21:30 +08:00
|
|
|
|
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void resetVar()
|
|
|
|
|
|
{
|
|
|
|
|
|
craftingFailed = false;
|
|
|
|
|
|
waitingForTable = false;
|
|
|
|
|
|
waitingForUpdate = false;
|
|
|
|
|
|
waitingForMaterials = false;
|
|
|
|
|
|
inventoryInUse = -2;
|
|
|
|
|
|
index = 0;
|
|
|
|
|
|
recipeInUse = null;
|
|
|
|
|
|
actionSteps.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-09 14:30:24 +08:00
|
|
|
|
private enum ActionType
|
|
|
|
|
|
{
|
2020-07-09 22:21:39 +08:00
|
|
|
|
LeftClick,
|
|
|
|
|
|
ShiftClick,
|
2020-07-09 14:30:24 +08:00
|
|
|
|
WaitForUpdate,
|
2020-07-09 22:21:39 +08:00
|
|
|
|
ResetCraftArea,
|
2021-01-15 20:25:23 +08:00
|
|
|
|
Repeat,
|
|
|
|
|
|
CheckResult
|
2020-07-09 14:30:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-12 19:21:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Represent a single action step of the whole crafting process
|
|
|
|
|
|
/// </summary>
|
2020-07-09 14:30:24 +08:00
|
|
|
|
private class ActionStep
|
|
|
|
|
|
{
|
2020-07-12 19:21:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The action type of this action step
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public ActionType ActionType;
|
2020-07-12 19:21:30 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// For storing data needed for processing
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>-2 mean not used</remarks>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public int Slot = -2;
|
2020-07-12 19:21:30 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// For storing data needed for processing
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>-2 mean not used</remarks>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public int InventoryID = -2;
|
2020-07-12 19:21:30 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// For storing data needed for processing
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public ItemType ItemType;
|
|
|
|
|
|
|
|
|
|
|
|
public ActionStep(ActionType actionType)
|
|
|
|
|
|
{
|
|
|
|
|
|
ActionType = actionType;
|
|
|
|
|
|
}
|
|
|
|
|
|
public ActionStep(ActionType actionType, int inventoryID)
|
|
|
|
|
|
{
|
|
|
|
|
|
ActionType = actionType;
|
|
|
|
|
|
InventoryID = inventoryID;
|
|
|
|
|
|
}
|
|
|
|
|
|
public ActionStep(ActionType actionType, int inventoryID, int slot)
|
|
|
|
|
|
{
|
|
|
|
|
|
ActionType = actionType;
|
|
|
|
|
|
Slot = slot;
|
|
|
|
|
|
InventoryID = inventoryID;
|
|
|
|
|
|
}
|
|
|
|
|
|
public ActionStep(ActionType actionType, int inventoryID, ItemType itemType)
|
|
|
|
|
|
{
|
|
|
|
|
|
ActionType = actionType;
|
|
|
|
|
|
InventoryID = inventoryID;
|
|
|
|
|
|
ItemType = itemType;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-12 19:21:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Represent a crafting recipe
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
private class Recipe
|
|
|
|
|
|
{
|
2020-07-12 19:21:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// The results item of this recipe
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public ItemType ResultItem;
|
2020-07-12 19:21:30 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Crafting table required for this recipe, playerInventory or Crafting
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public ContainerType CraftingAreaType;
|
2020-07-12 19:21:30 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Materials needed and their position
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks>position start with 1, from left to right, top to bottom</remarks>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public Dictionary<int, ItemType> Materials;
|
|
|
|
|
|
|
2020-07-19 21:27:01 +08:00
|
|
|
|
public Recipe() { }
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public Recipe(Dictionary<int, ItemType> materials, ItemType resultItem, ContainerType type)
|
|
|
|
|
|
{
|
|
|
|
|
|
Materials = materials;
|
|
|
|
|
|
ResultItem = resultItem;
|
|
|
|
|
|
CraftingAreaType = type;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-12 19:21:30 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Convert the position of a defined recipe from playerInventory to Crafting
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="recipe"></param>
|
|
|
|
|
|
/// <returns>Converted recipe</returns>
|
|
|
|
|
|
/// <remarks>so that it can be used in crafting table</remarks>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
public static Recipe ConvertToCraftingTable(Recipe recipe)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (recipe.CraftingAreaType == ContainerType.PlayerInventory)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (recipe.Materials.ContainsKey(4))
|
|
|
|
|
|
{
|
|
|
|
|
|
recipe.Materials[5] = recipe.Materials[4];
|
|
|
|
|
|
recipe.Materials.Remove(4);
|
|
|
|
|
|
}
|
|
|
|
|
|
if (recipe.Materials.ContainsKey(3))
|
|
|
|
|
|
{
|
|
|
|
|
|
recipe.Materials[4] = recipe.Materials[3];
|
|
|
|
|
|
recipe.Materials.Remove(3);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return recipe;
|
|
|
|
|
|
}
|
2020-07-09 14:30:24 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-23 20:32:02 +08:00
|
|
|
|
public AutoCraft(string configPath = @"autocraft\config.ini")
|
|
|
|
|
|
{
|
|
|
|
|
|
this.configPath = configPath;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-07 11:38:15 +08:00
|
|
|
|
public override void Initialize()
|
|
|
|
|
|
{
|
2020-07-20 19:33:57 +08:00
|
|
|
|
if (!GetInventoryEnabled())
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("extra.inventory_required");
|
|
|
|
|
|
LogToConsoleTranslated("general.bot_unload");
|
2020-07-20 19:33:57 +08:00
|
|
|
|
UnloadBot();
|
2020-08-17 22:02:00 +08:00
|
|
|
|
return;
|
2020-07-20 19:33:57 +08:00
|
|
|
|
}
|
2020-10-17 19:41:31 +08:00
|
|
|
|
RegisterChatBotCommand("autocraft", Translations.Get("bot.autoCraft.cmd"), GetHelp(), CommandHandler);
|
|
|
|
|
|
RegisterChatBotCommand("ac", Translations.Get("bot.autoCraft.alias"), GetHelp(), CommandHandler);
|
2020-07-20 19:33:57 +08:00
|
|
|
|
LoadConfig();
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public string CommandHandler(string cmd, string[] args)
|
|
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
if (args.Length > 0)
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
switch (args[0])
|
|
|
|
|
|
{
|
|
|
|
|
|
case "load":
|
|
|
|
|
|
LoadConfig();
|
|
|
|
|
|
return "";
|
|
|
|
|
|
case "list":
|
|
|
|
|
|
string names = string.Join(", ", recipes.Keys.ToList());
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autoCraft.cmd.list", recipes.Count, names);
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "reload":
|
|
|
|
|
|
recipes.Clear();
|
|
|
|
|
|
LoadConfig();
|
|
|
|
|
|
return "";
|
|
|
|
|
|
case "resetcfg":
|
|
|
|
|
|
WriteDefaultConfig();
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autoCraft.cmd.resetcfg");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "start":
|
|
|
|
|
|
if (args.Length >= 2)
|
|
|
|
|
|
{
|
|
|
|
|
|
string name = args[1];
|
|
|
|
|
|
if (recipes.ContainsKey(name))
|
|
|
|
|
|
{
|
|
|
|
|
|
resetVar();
|
|
|
|
|
|
PrepareCrafting(recipes[name]);
|
|
|
|
|
|
return "";
|
|
|
|
|
|
}
|
2020-10-17 19:41:31 +08:00
|
|
|
|
else return Translations.Get("bot.autoCraft.recipe_not_exist");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
2020-10-17 19:41:31 +08:00
|
|
|
|
else return Translations.Get("bot.autoCraft.no_recipe_name");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "stop":
|
|
|
|
|
|
StopCrafting();
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autoCraft.stop");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "help":
|
|
|
|
|
|
return GetCommandHelp(args.Length >= 2 ? args[1] : "");
|
|
|
|
|
|
default:
|
|
|
|
|
|
return GetHelp();
|
|
|
|
|
|
}
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
2020-07-20 19:21:52 +08:00
|
|
|
|
else return GetHelp();
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private string GetHelp()
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autoCraft.available_cmd", "load, list, reload, resetcfg, start, stop, help");
|
2020-07-07 11:38:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private string GetCommandHelp(string cmd)
|
2020-07-07 11:38:15 +08:00
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
switch (cmd.ToLower())
|
2020-07-07 11:38:15 +08:00
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "load":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.load");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "list":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.list");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "reload":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.reload");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "resetcfg":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.resetcfg");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "start":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.start");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "stop":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.stop");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "help":
|
2020-10-17 19:41:31 +08:00
|
|
|
|
return Translations.Get("bot.autocraft.help.help");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
default:
|
|
|
|
|
|
return GetHelp();
|
2020-07-07 11:38:15 +08:00
|
|
|
|
}
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region Config handling
|
|
|
|
|
|
|
|
|
|
|
|
public void LoadConfig()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!File.Exists(configPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!Directory.Exists(configPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Directory.CreateDirectory(@"autocraft");
|
|
|
|
|
|
}
|
|
|
|
|
|
WriteDefaultConfig();
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogDebugToConsoleTranslated("bot.autoCraft.debug.no_config");
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
ParseConfig();
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.loaded");
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.error.config", "\n" + e.Message);
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void WriteDefaultConfig()
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] content =
|
|
|
|
|
|
{
|
2020-07-23 20:32:02 +08:00
|
|
|
|
"[AutoCraft]",
|
|
|
|
|
|
"# A valid autocraft config must begin with [AutoCraft]",
|
2020-07-20 19:21:52 +08:00
|
|
|
|
"",
|
|
|
|
|
|
"tablelocation=0,65,0 # Location of the crafting table if you intended to use it. Terrain and movements must be enabled. Format: x,y,z",
|
|
|
|
|
|
"onfailure=abort # What to do on crafting failure, abort or wait",
|
|
|
|
|
|
"",
|
2020-07-23 20:32:02 +08:00
|
|
|
|
"# You can define multiple recipes in a single config file",
|
2020-07-20 19:21:52 +08:00
|
|
|
|
"# This is an example of how to define a recipe",
|
2020-07-23 20:32:02 +08:00
|
|
|
|
"[Recipe]",
|
|
|
|
|
|
"name=whatever # name could be whatever you like. This field must be defined first",
|
2020-07-20 19:21:52 +08:00
|
|
|
|
"type=player # crafting table type: player or table",
|
|
|
|
|
|
"result=StoneButton # the resulting item",
|
|
|
|
|
|
"",
|
2020-07-19 21:27:01 +08:00
|
|
|
|
"# define slots with their deserved item",
|
2020-07-20 19:21:52 +08:00
|
|
|
|
"slot1=Stone # slot start with 1, count from left to right, top to bottom",
|
2020-07-19 21:27:01 +08:00
|
|
|
|
"# For the naming of the items, please see",
|
2021-10-10 20:56:39 +02:00
|
|
|
|
"# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs"
|
2020-07-19 21:27:01 +08:00
|
|
|
|
};
|
|
|
|
|
|
File.WriteAllLines(configPath, content);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ParseConfig()
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] content = File.ReadAllLines(configPath);
|
2020-07-23 20:32:02 +08:00
|
|
|
|
if (content.Length <= 0)
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.empty", configPath));
|
2020-07-23 20:32:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
if (content[0].ToLower() != "[autocraft]")
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.invalid", configPath));
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// local variable for use in parsing config
|
2020-07-23 20:32:02 +08:00
|
|
|
|
string section = "";
|
2020-07-19 21:27:01 +08:00
|
|
|
|
Dictionary<string, Recipe> recipes = new Dictionary<string, Recipe>();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (string l in content)
|
|
|
|
|
|
{
|
|
|
|
|
|
// ignore comment start with #
|
2020-07-23 20:32:02 +08:00
|
|
|
|
if (l.StartsWith("#"))
|
|
|
|
|
|
continue;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
string line = l.Split('#')[0].Trim();
|
2020-07-23 20:32:02 +08:00
|
|
|
|
if (line.Length <= 0)
|
|
|
|
|
|
continue;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
|
|
|
|
|
|
if (line[0] == '[' && line[line.Length - 1] == ']')
|
|
|
|
|
|
{
|
2020-07-23 20:32:02 +08:00
|
|
|
|
section = line.Substring(1, line.Length - 2).ToLower();
|
2020-07-19 21:27:01 +08:00
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string key = line.Split('=')[0].ToLower();
|
2020-07-23 20:32:02 +08:00
|
|
|
|
if (!(line.Length > (key.Length + 1)))
|
|
|
|
|
|
continue;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
string value = line.Substring(key.Length + 1);
|
2020-07-23 20:32:02 +08:00
|
|
|
|
switch (section)
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-08-11 15:34:07 +08:00
|
|
|
|
case "recipe": parseRecipe(key, value); break;
|
2020-07-20 19:21:52 +08:00
|
|
|
|
case "autocraft": parseMain(key, value); break;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check and save recipe
|
2020-07-23 20:32:02 +08:00
|
|
|
|
foreach (var pair in recipes)
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
|
|
|
|
|
if ((pair.Value.CraftingAreaType == ContainerType.PlayerInventory
|
|
|
|
|
|
|| pair.Value.CraftingAreaType == ContainerType.Crafting)
|
|
|
|
|
|
&& (pair.Value.Materials != null
|
|
|
|
|
|
&& pair.Value.Materials.Count > 0)
|
|
|
|
|
|
&& pair.Value.ResultItem != ItemType.Air)
|
|
|
|
|
|
{
|
|
|
|
|
|
// checking pass
|
|
|
|
|
|
this.recipes.Add(pair.Key, pair.Value);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.item_miss", pair.Key));
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-24 10:51:35 +08:00
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#region Method for parsing different section of config
|
2020-07-19 21:27:01 +08:00
|
|
|
|
|
2020-07-24 10:51:35 +08:00
|
|
|
|
private void parseMain(string key, string value)
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (key)
|
2020-07-20 19:21:52 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
case "tablelocation":
|
|
|
|
|
|
string[] values = value.Split(',');
|
|
|
|
|
|
if (values.Length == 3)
|
|
|
|
|
|
{
|
|
|
|
|
|
tableLocation.X = Convert.ToInt32(values[0]);
|
|
|
|
|
|
tableLocation.Y = Convert.ToInt32(values[1]);
|
|
|
|
|
|
tableLocation.Z = Convert.ToInt32(values[2]);
|
|
|
|
|
|
}
|
2020-10-17 19:41:31 +08:00
|
|
|
|
else throw new Exception(Translations.Get("bot.autoCraft.exception.invalid_table", key));
|
2020-07-24 10:51:35 +08:00
|
|
|
|
break;
|
|
|
|
|
|
case "onfailure":
|
|
|
|
|
|
abortOnFailure = value.ToLower() == "abort" ? true : false;
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "updatedebounce":
|
|
|
|
|
|
updateDebounceValue = Convert.ToInt32(value);
|
|
|
|
|
|
break;
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
2020-07-24 10:51:35 +08:00
|
|
|
|
}
|
2020-07-20 19:21:52 +08:00
|
|
|
|
|
2020-08-11 15:34:07 +08:00
|
|
|
|
private void parseRecipe(string key, string value)
|
2020-07-24 10:51:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (key.StartsWith("slot"))
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
int slot = Convert.ToInt32(key[key.Length - 1].ToString());
|
|
|
|
|
|
if (slot > 0 && slot < 10)
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
if (recipes.ContainsKey(lastRecipe))
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 12:36:21 +02:00
|
|
|
|
ItemType itemType;
|
2020-07-31 03:06:36 +08:00
|
|
|
|
if (Enum.TryParse(value, true, out itemType))
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
if (recipes[lastRecipe].Materials != null && recipes[lastRecipe].Materials.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
recipes[lastRecipe].Materials.Add(slot, itemType);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
recipes[lastRecipe].Materials = new Dictionary<int, ItemType>()
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
|
|
|
|
|
{ slot, itemType }
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
2020-07-24 10:51:35 +08:00
|
|
|
|
return;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
2020-08-11 15:34:07 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.item_name", lastRecipe, key));
|
2020-08-11 15:34:07 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.name_miss"));
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-08-11 15:34:07 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.slot", key));
|
2020-08-11 15:34:07 +08:00
|
|
|
|
}
|
2020-07-24 10:51:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
switch (key)
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
case "name":
|
|
|
|
|
|
if (!recipes.ContainsKey(value))
|
|
|
|
|
|
{
|
|
|
|
|
|
recipes.Add(value, new Recipe());
|
|
|
|
|
|
lastRecipe = value;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
throw new Exception(Translations.Get("bot.autoCraft.exception.duplicate", value));
|
2020-07-24 10:51:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "type":
|
|
|
|
|
|
if (recipes.ContainsKey(lastRecipe))
|
|
|
|
|
|
{
|
|
|
|
|
|
recipes[lastRecipe].CraftingAreaType = value.ToLower() == "player" ? ContainerType.PlayerInventory : ContainerType.Crafting;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "result":
|
|
|
|
|
|
if (recipes.ContainsKey(lastRecipe))
|
|
|
|
|
|
{
|
2020-07-24 12:36:21 +02:00
|
|
|
|
ItemType itemType;
|
2020-07-31 03:06:36 +08:00
|
|
|
|
if (Enum.TryParse(value, true, out itemType))
|
2020-07-19 21:27:01 +08:00
|
|
|
|
{
|
2020-07-24 10:51:35 +08:00
|
|
|
|
recipes[lastRecipe].ResultItem = itemType;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
2020-07-24 10:51:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
break;
|
2020-07-19 21:27:01 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-07-24 10:51:35 +08:00
|
|
|
|
#endregion
|
2020-07-19 21:27:01 +08:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Core part of auto-crafting
|
|
|
|
|
|
|
2020-07-07 11:38:15 +08:00
|
|
|
|
public override void OnInventoryUpdate(int inventoryId)
|
|
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
if ((waitingForUpdate && inventoryInUse == inventoryId) || (waitingForMaterials && inventoryInUse == inventoryId))
|
2020-07-07 11:38:15 +08:00
|
|
|
|
{
|
2020-07-12 19:21:30 +08:00
|
|
|
|
// Because server might send us a LOT of update at once, even there is only a single slot updated.
|
|
|
|
|
|
// Using this to make sure we don't do things before inventory update finish
|
2020-07-20 19:21:52 +08:00
|
|
|
|
updateDebounce = updateDebounceValue;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void OnInventoryOpen(int inventoryId)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (waitingForTable)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (GetInventories()[inventoryId].Type == ContainerType.Crafting)
|
|
|
|
|
|
{
|
|
|
|
|
|
waitingForTable = false;
|
|
|
|
|
|
ClearTimeout();
|
|
|
|
|
|
// After table opened, we need to wait for server to update table inventory items
|
|
|
|
|
|
waitingForUpdate = true;
|
|
|
|
|
|
inventoryInUse = inventoryId;
|
|
|
|
|
|
PrepareCrafting(recipeInUse);
|
|
|
|
|
|
}
|
2020-07-09 22:21:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void Update()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (updateDebounce > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
updateDebounce--;
|
|
|
|
|
|
if (updateDebounce <= 0)
|
|
|
|
|
|
InventoryUpdateFinished();
|
|
|
|
|
|
}
|
2020-07-20 19:21:52 +08:00
|
|
|
|
if (updateTimeout > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
updateTimeout--;
|
|
|
|
|
|
if (updateTimeout <= 0)
|
|
|
|
|
|
HandleUpdateTimeout();
|
|
|
|
|
|
}
|
2020-07-09 22:21:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void InventoryUpdateFinished()
|
|
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
if (waitingForUpdate || waitingForMaterials)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (waitingForUpdate)
|
|
|
|
|
|
waitingForUpdate = false;
|
|
|
|
|
|
if (waitingForMaterials)
|
|
|
|
|
|
{
|
|
|
|
|
|
waitingForMaterials = false;
|
|
|
|
|
|
craftingFailed = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
HandleNextStep();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OpenTable(Location location)
|
|
|
|
|
|
{
|
|
|
|
|
|
SendPlaceBlock(location, Direction.Up);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-22 19:01:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Prepare the crafting action steps by the given recipe name and start crafting
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="recipe">Name of the recipe to craft</param>
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void PrepareCrafting(string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
PrepareCrafting(recipes[name]);
|
|
|
|
|
|
}
|
2020-07-22 19:01:43 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Prepare the crafting action steps by the given recipe and start crafting
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="recipe">Recipe to craft</param>
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void PrepareCrafting(Recipe recipe)
|
|
|
|
|
|
{
|
|
|
|
|
|
recipeInUse = recipe;
|
|
|
|
|
|
if (recipeInUse.CraftingAreaType == ContainerType.PlayerInventory)
|
|
|
|
|
|
inventoryInUse = 0;
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var inventories = GetInventories();
|
|
|
|
|
|
foreach (var inventory in inventories)
|
|
|
|
|
|
if (inventory.Value.Type == ContainerType.Crafting)
|
|
|
|
|
|
inventoryInUse = inventory.Key;
|
|
|
|
|
|
if (inventoryInUse == -2)
|
|
|
|
|
|
{
|
|
|
|
|
|
// table required but not found. Try to open one
|
|
|
|
|
|
OpenTable(tableLocation);
|
|
|
|
|
|
waitingForTable = true;
|
2020-10-17 19:41:31 +08:00
|
|
|
|
SetTimeout(Translations.Get("bot.autoCraft.table_not_found"));
|
2020-07-20 19:21:52 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (KeyValuePair<int, ItemType> slot in recipe.Materials)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Steps for moving items from inventory to crafting area
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.LeftClick, inventoryInUse, slot.Value));
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.LeftClick, inventoryInUse, slot.Key));
|
|
|
|
|
|
}
|
|
|
|
|
|
if (actionSteps.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Wait for server to send us the crafting result
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.WaitForUpdate, inventoryInUse, 0));
|
2021-01-15 20:25:23 +08:00
|
|
|
|
// Check the crafting result is the item we want
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.CheckResult, inventoryInUse, recipe.ResultItem));
|
2020-07-20 19:21:52 +08:00
|
|
|
|
// Put item back to inventory. (Using shift-click can take all item at once)
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.ShiftClick, inventoryInUse, 0));
|
|
|
|
|
|
// We need to wait for server to update us after taking item from crafting result
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.WaitForUpdate, inventoryInUse));
|
|
|
|
|
|
// Repeat the whole process again
|
|
|
|
|
|
actionSteps.Add(new ActionStep(ActionType.Repeat));
|
|
|
|
|
|
// Start crafting
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.start", recipe.ResultItem);
|
2020-07-20 19:21:52 +08:00
|
|
|
|
HandleNextStep();
|
|
|
|
|
|
}
|
2020-10-17 19:41:31 +08:00
|
|
|
|
else LogToConsoleTranslated("bot.autoCraft.start_fail", recipe.ResultItem);
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-22 19:01:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Stop the crafting process by clearing crafting action steps and close the inventory
|
|
|
|
|
|
/// </summary>
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void StopCrafting()
|
|
|
|
|
|
{
|
|
|
|
|
|
actionSteps.Clear();
|
2021-01-15 20:25:23 +08:00
|
|
|
|
// Put item back to inventory or they will be dropped
|
|
|
|
|
|
ClearCraftingArea(inventoryInUse);
|
2020-07-20 19:21:52 +08:00
|
|
|
|
// Closing inventory can make server to update our inventory
|
|
|
|
|
|
// Useful when
|
|
|
|
|
|
// - There are some items left in the crafting area
|
|
|
|
|
|
// - Resynchronize player inventory if using crafting table
|
|
|
|
|
|
if (GetInventories().ContainsKey(inventoryInUse))
|
|
|
|
|
|
{
|
|
|
|
|
|
CloseInventory(inventoryInUse);
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.close_inventory", inventoryInUse);
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
2020-07-09 22:21:39 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-22 19:01:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Handle next crafting action step
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
private void HandleNextStep()
|
|
|
|
|
|
{
|
|
|
|
|
|
while (actionSteps.Count > 0)
|
|
|
|
|
|
{
|
2020-07-20 19:21:52 +08:00
|
|
|
|
if (waitingForUpdate || waitingForMaterials || craftingFailed) break;
|
2020-07-09 22:21:39 +08:00
|
|
|
|
ActionStep step = actionSteps[index];
|
|
|
|
|
|
index++;
|
|
|
|
|
|
switch (step.ActionType)
|
2020-07-07 11:38:15 +08:00
|
|
|
|
{
|
2020-07-09 22:21:39 +08:00
|
|
|
|
case ActionType.LeftClick:
|
|
|
|
|
|
if (step.Slot != -2)
|
|
|
|
|
|
{
|
|
|
|
|
|
WindowAction(step.InventoryID, step.Slot, WindowActionType.LeftClick);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
int[] slots = GetInventories()[step.InventoryID].SearchItem(step.ItemType);
|
|
|
|
|
|
if (slots.Count() > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
int ignoredSlot;
|
|
|
|
|
|
if (recipeInUse.CraftingAreaType == ContainerType.PlayerInventory)
|
|
|
|
|
|
ignoredSlot = 9;
|
|
|
|
|
|
else
|
|
|
|
|
|
ignoredSlot = 10;
|
|
|
|
|
|
slots = slots.Where(slot => slot >= ignoredSlot).ToArray();
|
|
|
|
|
|
if (slots.Count() > 0)
|
|
|
|
|
|
WindowAction(step.InventoryID, slots[0], WindowActionType.LeftClick);
|
|
|
|
|
|
else
|
|
|
|
|
|
craftingFailed = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else craftingFailed = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.ShiftClick:
|
|
|
|
|
|
if (step.Slot == 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
WindowAction(step.InventoryID, step.Slot, WindowActionType.ShiftClick);
|
|
|
|
|
|
}
|
|
|
|
|
|
else craftingFailed = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2021-01-15 20:25:23 +08:00
|
|
|
|
// Compare the crafting result with the recipe result
|
|
|
|
|
|
case ActionType.CheckResult:
|
|
|
|
|
|
if (GetInventories()[step.InventoryID].Items.ContainsKey(0)
|
|
|
|
|
|
&& GetInventories()[step.InventoryID].Items[0].Type == step.ItemType)
|
|
|
|
|
|
{
|
|
|
|
|
|
// OK
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// Bad, reset everything
|
|
|
|
|
|
ClearCraftingArea(step.InventoryID);
|
|
|
|
|
|
index = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
2020-07-09 22:21:39 +08:00
|
|
|
|
case ActionType.WaitForUpdate:
|
|
|
|
|
|
if (step.InventoryID != -2)
|
|
|
|
|
|
{
|
|
|
|
|
|
waitingForUpdate = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
else craftingFailed = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.ResetCraftArea:
|
|
|
|
|
|
if (step.InventoryID != -2)
|
2021-01-15 20:25:23 +08:00
|
|
|
|
ClearCraftingArea(step.InventoryID);
|
2020-07-09 22:21:39 +08:00
|
|
|
|
else
|
|
|
|
|
|
craftingFailed = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case ActionType.Repeat:
|
|
|
|
|
|
index = 0;
|
|
|
|
|
|
break;
|
2020-07-07 11:38:15 +08:00
|
|
|
|
}
|
2020-07-09 22:21:39 +08:00
|
|
|
|
HandleError();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-22 19:01:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Handle any crafting error after a step was processed
|
|
|
|
|
|
/// </summary>
|
2020-07-09 22:21:39 +08:00
|
|
|
|
private void HandleError()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (craftingFailed)
|
|
|
|
|
|
{
|
2020-08-11 15:34:07 +08:00
|
|
|
|
if (actionSteps[index - 1].ActionType == ActionType.LeftClick && actionSteps[index - 1].ItemType != ItemType.Air)
|
|
|
|
|
|
{
|
|
|
|
|
|
// Inform user the missing meterial name
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.missing_material", actionSteps[index - 1].ItemType.ToString());
|
2020-08-11 15:34:07 +08:00
|
|
|
|
}
|
2020-07-20 19:21:52 +08:00
|
|
|
|
if (abortOnFailure)
|
|
|
|
|
|
{
|
|
|
|
|
|
StopCrafting();
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.aborted");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
waitingForMaterials = true;
|
|
|
|
|
|
// Even though crafting failed, action step index will still increase
|
|
|
|
|
|
// we want to do that failed step again so decrease index by 1
|
|
|
|
|
|
index--;
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.craft_fail");
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
2020-07-07 11:38:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2020-07-19 21:27:01 +08:00
|
|
|
|
|
2021-01-15 20:25:23 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Put any item left in the crafting area back to inventory
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="inventoryId">Inventory ID to operate with</param>
|
|
|
|
|
|
private void ClearCraftingArea(int inventoryId)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (GetInventories().ContainsKey(inventoryId))
|
|
|
|
|
|
{
|
|
|
|
|
|
var inventory = GetInventories()[inventoryId];
|
|
|
|
|
|
int areaStart = 1;
|
|
|
|
|
|
int areaEnd = 4;
|
|
|
|
|
|
if (inventory.Type == ContainerType.Crafting)
|
|
|
|
|
|
{
|
|
|
|
|
|
areaEnd = 9;
|
|
|
|
|
|
}
|
|
|
|
|
|
List<int> emptySlots = inventory.GetEmpytSlots().Where(s => s > 9).ToList();
|
|
|
|
|
|
for (int i = areaStart; i <= areaEnd; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (inventory.Items.ContainsKey(i))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (emptySlots.Count != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
WindowAction(inventoryId, i, WindowActionType.LeftClick);
|
|
|
|
|
|
WindowAction(inventoryId, emptySlots[0], WindowActionType.LeftClick);
|
|
|
|
|
|
emptySlots.RemoveAt(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
WindowAction(inventoryId, i, WindowActionType.DropItemStack);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void HandleUpdateTimeout()
|
|
|
|
|
|
{
|
2020-10-17 19:41:31 +08:00
|
|
|
|
LogToConsoleTranslated("bot.autoCraft.timeout", timeoutAction);
|
2020-07-20 19:21:52 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-22 19:01:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Set the timeout. Used to detect the failure of open crafting table
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="reason">The reason to display if timeout</param>
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void SetTimeout(string reason = "unspecified")
|
|
|
|
|
|
{
|
|
|
|
|
|
updateTimeout = updateTimeoutValue;
|
|
|
|
|
|
timeoutAction = reason;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-22 19:01:43 +08:00
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Clear the timeout
|
|
|
|
|
|
/// </summary>
|
2020-07-20 19:21:52 +08:00
|
|
|
|
private void ClearTimeout()
|
|
|
|
|
|
{
|
|
|
|
|
|
updateTimeout = 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-07-19 21:27:01 +08:00
|
|
|
|
#endregion
|
2020-07-07 11:38:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|