Add config support

This commit is contained in:
ReinforceZwei 2020-07-19 21:27:01 +08:00 committed by ORelio
parent b05e1a872d
commit a8464077a1

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping;
@ -10,15 +11,17 @@ namespace MinecraftClient.ChatBots
class AutoCarft : ChatBot
{
private bool waitingForUpdate = false;
private bool craftingFailed = false;
private int inventoryInUse = -2;
private int index = 0;
private Recipe recipeInUse;
private List<ActionStep> actionSteps = new List<ActionStep>();
private int updateDebounce = 0;
private bool craftingFailed = false;
private string configPath = @"autocraft\config.ini";
private List<ActionStep> actionSteps = new List<ActionStep>();
private Dictionary<string, Recipe> recipes = new Dictionary<string, Recipe>();
private enum ActionType
{
@ -100,6 +103,7 @@ namespace MinecraftClient.ChatBots
/// <remarks>position start with 1, from left to right, top to bottom</remarks>
public Dictionary<int, ItemType> Materials;
public Recipe() { }
public Recipe(Dictionary<int, ItemType> materials, ItemType resultItem, ContainerType type)
{
Materials = materials;
@ -135,6 +139,35 @@ namespace MinecraftClient.ChatBots
public override void Initialize()
{
RegisterChatBotCommand("craft", "craft", CraftCommand);
RegisterChatBotCommand("open", "open", Open);
RegisterChatBotCommand("autocraft", "auto craft", CommandHandler);
}
public string CommandHandler(string cmd, string[] args)
{
switch (args[0])
{
case "load":
LoadConfig();
return "";
case "list":
string names = string.Join(", ", recipes.Keys.ToList());
return String.Format("Total {0} recipes loaded: {1}", recipes.Count, names);
case "reload":
recipes.Clear();
LoadConfig();
return "";
}
return "";
}
public string Open(string cmd, string[] args)
{
double x = Convert.ToDouble(args[0]);
double y = Convert.ToDouble(args[1]);
double z = Convert.ToDouble(args[2]);
SendPlaceBlock(new Location(x, y, z), .5f, .5f, .5f, Direction.Up);
return "ok";
}
public string CraftCommand(string command, string[] args)
@ -178,6 +211,185 @@ namespace MinecraftClient.ChatBots
else return "AutoCraft cannot be started. Check your available materials";
}
public string LoadConfigRunner(string command, string[] args)
{
LoadConfig();
return "ok";
}
#region Config handling
public void LoadConfig()
{
if (!File.Exists(configPath))
{
if (!Directory.Exists(configPath))
{
Directory.CreateDirectory(@"autocraft");
}
WriteDefaultConfig();
ConsoleIO.WriteLogLine("No config found. Writing a new one.");
}
try
{
ParseConfig();
ConsoleIO.WriteLogLine("Successfully loaded");
}
catch (Exception e)
{
ConsoleIO.WriteLogLine("Error while parsing config: \n" + e.Message);
}
}
private void WriteDefaultConfig()
{
string[] content =
{
"[autocraft]",
"# A vaild autocraft config must begin with [autocraft]",
"# You can define multiple recipe in the config file",
"# This is a example of how to define a recipe",
"[recipe]",
"# name could be whatever you like. This must be in the first place",
"name=whatever",
"# crafting table type: player or table",
"type=player",
"# the resulting item",
"result=StoneButton",
"# define slots with their deserved item",
"# slot start with 1, count from top to bottom, left to right",
"slot1=Stone",
"# For the naming of the items, please see",
"# https://github.com/ORelio/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs"
};
File.WriteAllLines(configPath, content);
}
private void ParseConfig()
{
string[] content = File.ReadAllLines(configPath);
if (content[0] != "[autocraft]")
{
throw new Exception("Cannot parse this config");
}
// local variable for use in parsing config
string session = "";
Dictionary<string, Recipe> recipes = new Dictionary<string, Recipe>();
string lastRecipe = "";
foreach (string l in content)
{
// ignore comment start with #
if (l.StartsWith("#")) continue;
string line = l.Split('#')[0].Trim();
if (line.Length <= 0) continue;
if (line[0] == '[' && line[line.Length - 1] == ']')
{
session = line.Substring(1, line.Length - 2).ToLower();
continue;
}
string key = line.Split('=')[0].ToLower();
if (!(line.Length > (key.Length + 1))) continue;
string value = line.Substring(key.Length + 1);
switch (session)
{
case "recipe":
parseRecipe(key, value);
break;
}
}
// check and save recipe
foreach(var pair in recipes)
{
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
{
throw new Exception("Missing item in recipe");
}
}
#region Local method for parsing different session of config
void parseRecipe(string key, string value)
{
if (key.StartsWith("slot"))
{
int slot = Convert.ToInt32(key[key.Length - 1].ToString());
if (slot > 0 && slot < 10)
{
if (recipes.ContainsKey(lastRecipe))
{
if (Enum.TryParse(value, out ItemType itemType))
{
if (recipes[lastRecipe].Materials != null && recipes[lastRecipe].Materials.Count > 0)
{
recipes[lastRecipe].Materials.Add(slot, itemType);
}
else
{
recipes[lastRecipe].Materials = new Dictionary<int, ItemType>()
{
{ slot, itemType }
};
}
return;
}
}
}
throw new Exception("Invalid config format");
}
else
{
switch (key)
{
case "name":
if (!recipes.ContainsKey(value))
{
recipes.Add(value, new Recipe());
lastRecipe = value;
}
else
{
throw new Exception("Duplicate recipe name specified");
}
break;
case "type":
if (recipes.ContainsKey(lastRecipe))
{
recipes[lastRecipe].CraftingAreaType = value.ToLower() == "player" ? ContainerType.PlayerInventory : ContainerType.Crafting;
}
break;
case "result":
if (recipes.ContainsKey(lastRecipe))
{
if (Enum.TryParse(value, out ItemType itemType))
{
recipes[lastRecipe].ResultItem = itemType;
}
}
break;
}
}
}
#endregion
}
#endregion
#region Core part of auto-crafting
public override void OnInventoryUpdate(int inventoryId)
{
if (waitingForUpdate && inventoryInUse == inventoryId)
@ -283,5 +495,7 @@ namespace MinecraftClient.ChatBots
ConsoleIO.WriteLogLine("Crafting aborted! Check your available materials.");
}
}
#endregion
}
}