Add AutoDig ChatBot

This commit is contained in:
BruceChen 2022-10-08 17:56:32 +08:00
parent 4cb95731bf
commit c57ac183d5
16 changed files with 579 additions and 64 deletions

View file

@ -38,9 +38,6 @@ namespace MinecraftClient.ChatBots
[TomlInlineComment("$config.ChatBot.AntiAfk.Walk_Retries$")] [TomlInlineComment("$config.ChatBot.AntiAfk.Walk_Retries$")]
public int Walk_Retries = 20; public int Walk_Retries = 20;
[NonSerialized]
public int _DelayMin, _DelayMax;
public void OnSettingUpdate() public void OnSettingUpdate()
{ {
if (Walk_Range <= 0) if (Walk_Range <= 0)
@ -61,9 +58,6 @@ namespace MinecraftClient.ChatBots
LogToConsole(BotName, Translations.TryGet("bot.antiafk.swapping")); LogToConsole(BotName, Translations.TryGet("bot.antiafk.swapping"));
} }
_DelayMin = (int)Math.Round(Delay.min * 10);
_DelayMax = (int)Math.Round(Delay.max * 10);
Command ??= string.Empty; Command ??= string.Empty;
} }
@ -115,7 +109,7 @@ namespace MinecraftClient.ChatBots
{ {
DoAntiAfkStuff(); DoAntiAfkStuff();
count = 0; count = 0;
nextrun = random.Next(Config._DelayMin, Config._DelayMax); nextrun = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max));
} }
} }

View file

@ -0,0 +1,392 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Metrics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MinecraftClient.Inventory;
using MinecraftClient.Mapping;
using MinecraftClient.Mapping.BlockPalettes;
using Tomlet.Attributes;
using static MinecraftClient.ChatBots.AutoCraft.Configs;
namespace MinecraftClient.ChatBots
{
public class AutoDig : ChatBot
{
public static Configs Config = new();
[TomlDoNotInlineObject]
public class Configs
{
[NonSerialized]
private const string BotName = "AutoDig";
public bool Enabled = false;
[NonSerialized]
[TomlInlineComment("$config.ChatBot.AutoDig.Auto_Tool_Switch$")]
public bool Auto_Tool_Switch = false;
[NonSerialized]
[TomlInlineComment("$config.ChatBot.AutoDig.Durability_Limit$")]
public int Durability_Limit = 2;
[NonSerialized]
[TomlInlineComment("$config.ChatBot.AutoDig.Drop_Low_Durability_Tools$")]
public bool Drop_Low_Durability_Tools = false;
[TomlInlineComment("$config.ChatBot.AutoDig.Mode$")]
public ModeType Mode = ModeType.lookat;
[TomlInlineComment("$config.ChatBot.AutoDig.Locations$")]
public Coordination[] Locations = new Coordination[] { new(123.5, 64, 234.5), new(124.5, 63, 235.5) };
[TomlInlineComment("$config.ChatBot.AutoDig.Auto_Start_Delay$")]
public double Auto_Start_Delay = 3.0;
[TomlInlineComment("$config.ChatBot.AutoDig.Dig_Timeout$")]
public double Dig_Timeout = 30.0;
[TomlInlineComment("$config.ChatBot.AutoDig.Log_Block_Dig$")]
public bool Log_Block_Dig = true;
[TomlInlineComment("$config.ChatBot.AutoDig.List_Type$")]
public ListType List_Type = ListType.whitelist;
public List<Material> Blocks = new() { Material.Cobblestone, Material.Stone };
[NonSerialized]
public Location[] _Locations = Array.Empty<Location>();
public void OnSettingUpdate()
{
if (Auto_Start_Delay >= 0)
Auto_Start_Delay = Math.Max(0.1, Auto_Start_Delay);
if (Dig_Timeout >= 0)
Dig_Timeout = Math.Max(0.1, Dig_Timeout);
_Locations = new Location[Locations.Length];
for (int i = 0; i < Locations.Length; ++i)
_Locations[i] = new(Locations[i].x, Locations[i].y, Locations[i].z);
}
public enum ModeType { lookat, fixedpos, both };
public enum ListType { blacklist, whitelist };
public struct Coordination
{
public double x, y, z;
public Coordination(double x, double y, double z)
{
this.x = x; this.y = y; this.z = z;
}
}
}
private bool inventoryEnabled;
private int counter = 0;
private readonly object stateLock = new();
private State state = State.WaitJoinGame;
bool AlreadyWaitting = false;
private Location currentDig = Location.Zero;
private enum State
{
WaitJoinGame,
WaitingStart,
Digging,
Stopping,
}
public override void Initialize()
{
if (!GetTerrainEnabled())
{
LogToConsoleTranslated("extra.terrainandmovement_required");
LogToConsoleTranslated("general.bot_unload");
UnloadBot();
return;
}
inventoryEnabled = GetInventoryEnabled();
if (!inventoryEnabled && Config.Auto_Tool_Switch)
LogToConsoleTranslated("bot.autodig.no_inv_handle");
RegisterChatBotCommand("digbot", Translations.Get("bot.digbot.cmd"), GetHelp(), CommandHandler);
}
public string CommandHandler(string cmd, string[] args)
{
if (args.Length > 0)
{
switch (args[0])
{
case "start":
lock (stateLock)
{
counter = 0;
state = State.WaitingStart;
}
return Translations.Get("bot.autodig.start");
case "stop":
StopDigging();
return Translations.Get("bot.autodig.stop");
case "help":
return GetCommandHelp(args.Length >= 2 ? args[1] : "");
default:
return GetHelp();
}
}
else return GetHelp();
}
private void StartDigging()
{
if (Config.Auto_Start_Delay > 0)
{
double delay = Config.Auto_Start_Delay;
LogToConsole(Translations.Get("bot.autodig.start_delay", delay));
lock (stateLock)
{
counter = Settings.DoubleToTick(delay);
state = State.WaitingStart;
}
}
else
{
lock (stateLock)
{
state = State.WaitJoinGame;
}
}
}
private void StopDigging()
{
state = State.Stopping;
lock (stateLock)
{
state = State.Stopping;
}
}
public override void Update()
{
lock (stateLock)
{
switch (state)
{
case State.WaitJoinGame:
break;
case State.WaitingStart:
if (--counter < 0)
{
if (DoDigging())
{
AlreadyWaitting = false;
state = State.Digging;
}
else
{
counter = 0;
state = State.WaitingStart;
}
}
break;
case State.Digging:
if (++counter > Settings.DoubleToTick(Config.Dig_Timeout))
{
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autodig.dig_timeout"));
state = State.WaitingStart;
counter = 0;
}
break;
case State.Stopping:
break;
}
}
}
private bool DoDigging()
{
if (Config.Mode == Configs.ModeType.lookat || Config.Mode == Configs.ModeType.both)
{
(bool hasBlock, Location blockLoc, Block block) = GetLookingBlock(4.5, false);
if (!hasBlock)
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.too_far"));
}
return false;
}
else if (block.Type == Material.Air)
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.no_block"));
}
return false;
}
else if ((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type)))
{
if (Config.Mode == Configs.ModeType.lookat ||
(Config.Mode == Configs.ModeType.both && Config._Locations.Contains(blockLoc)))
{
if (DigBlock(blockLoc, lookAtBlock: false))
{
currentDig = blockLoc;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.dig", blockLoc.X, blockLoc.Y, blockLoc.Z, block.Type));
return true;
}
else
{
LogToConsole(Translations.Get("cmd.dig.fail"));
return false;
}
}
else
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("bot.autodig.not_allow"));
}
return false;
}
}
else
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("bot.autodig.not_allow"));
}
return false;
}
}
else if (Config.Mode == Configs.ModeType.fixedpos)
{
Location current = GetCurrentLocation();
double minDistance = double.MaxValue;
Location target = Location.Zero;
Block targetBlock = Block.Air;
foreach (Location location in Config._Locations)
{
Block block = GetWorld().GetBlock(location);
if (block.Type != Material.Air &&
((Config.List_Type == Configs.ListType.whitelist && Config.Blocks.Contains(block.Type)) ||
(Config.List_Type == Configs.ListType.blacklist && !Config.Blocks.Contains(block.Type))))
{
double distance = current.Distance(location);
if (distance < minDistance)
{
minDistance = distance;
target = location;
targetBlock = block;
}
}
}
if (minDistance <= 6.0)
{
if (DigBlock(target, lookAtBlock: true))
{
currentDig = target;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.dig", target.X, target.Y, target.Z, targetBlock.Type));
return true;
}
else
{
LogToConsole(Translations.Get("cmd.dig.fail"));
return false;
}
}
else
{
if (!AlreadyWaitting)
{
AlreadyWaitting = true;
if (Config.Log_Block_Dig)
LogToConsole(Translations.Get("cmd.dig.no_block"));
}
return false;
}
}
return false;
}
public override void OnBlockChange(Location location, Block block)
{
if (location == currentDig)
{
lock (stateLock)
{
if (state == State.Digging && location == currentDig)
{
currentDig = Location.Zero;
counter = 0;
state = State.WaitingStart;
}
}
}
}
public override void AfterGameJoined()
{
StartDigging();
}
public override void OnRespawn()
{
StartDigging();
}
public override void OnDeath()
{
StopDigging();
}
public override bool OnDisconnect(DisconnectReason reason, string message)
{
StopDigging();
return base.OnDisconnect(reason, message);
}
private static string GetHelp()
{
return Translations.Get("bot.autodig.available_cmd", "start, stop, help");
}
private string GetCommandHelp(string cmd)
{
return cmd.ToLower() switch
{
#pragma warning disable format // @formatter:off
"start" => Translations.Get("bot.autodig.help.start"),
"stop" => Translations.Get("bot.autodig.help.stop"),
"help" => Translations.Get("bot.autodig.help.help"),
_ => GetHelp(),
#pragma warning restore format // @formatter:on
};
}
}
}

View file

@ -184,7 +184,7 @@ namespace MinecraftClient.ChatBots
LogToConsole(Translations.Get("bot.autoFish.start", delay)); LogToConsole(Translations.Get("bot.autoFish.start", delay));
lock (stateLock) lock (stateLock)
{ {
counter = (int)(delay * 10); counter = Settings.DoubleToTick(delay);
state = FishingState.StartMove; state = FishingState.StartMove;
} }
} }
@ -224,7 +224,7 @@ namespace MinecraftClient.ChatBots
break; break;
case FishingState.WaitingToCast: case FishingState.WaitingToCast:
if (AutoEat.Eating) if (AutoEat.Eating)
counter = (int)(Config.Cast_Delay * 10); counter = Settings.DoubleToTick(Config.Cast_Delay);
else if (--counter < 0) else if (--counter < 0)
state = FishingState.CastingRod; state = FishingState.CastingRod;
break; break;
@ -240,16 +240,16 @@ namespace MinecraftClient.ChatBots
castTimeout *= 2; // Exponential backoff castTimeout *= 2; // Exponential backoff
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.cast_timeout", castTimeout / 10.0)); LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.cast_timeout", castTimeout / 10.0));
counter = (int)(Config.Cast_Delay * 10); counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast; state = FishingState.WaitingToCast;
} }
break; break;
case FishingState.WaitingFishToBite: case FishingState.WaitingFishToBite:
if (++counter > (int)(Config.Fishing_Timeout * 10)) if (++counter > Settings.DoubleToTick(Config.Fishing_Timeout))
{ {
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.fishing_timeout")); LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.fishing_timeout"));
counter = (int)(Config.Cast_Delay * 10); counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast; state = FishingState.WaitingToCast;
} }
break; break;
@ -271,7 +271,7 @@ namespace MinecraftClient.ChatBots
} }
else else
{ {
counter = (int)(Config.Cast_Delay * 10); counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.DurabilityCheck; state = FishingState.DurabilityCheck;
goto case FishingState.DurabilityCheck; goto case FishingState.DurabilityCheck;
} }
@ -290,7 +290,7 @@ namespace MinecraftClient.ChatBots
case FishingState.DurabilityCheck: case FishingState.DurabilityCheck:
if (DurabilityCheck()) if (DurabilityCheck())
{ {
counter = (int)(Config.Cast_Delay * 10); counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast; state = FishingState.WaitingToCast;
} }
break; break;
@ -338,7 +338,7 @@ namespace MinecraftClient.ChatBots
lock (stateLock) lock (stateLock)
{ {
counter = (int)(Config.Cast_Delay * 10); counter = Settings.DoubleToTick(Config.Cast_Delay);
state = FishingState.WaitingToCast; state = FishingState.WaitingToCast;
} }
} }

View file

@ -129,7 +129,7 @@ namespace MinecraftClient.ChatBots
private void LaunchDelayedReconnection(string? msg) private void LaunchDelayedReconnection(string? msg)
{ {
int delay = random.Next((int)Config.Delay.min, (int)Config.Delay.max); int delay = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max));
LogDebugToConsoleTranslated(String.IsNullOrEmpty(msg) ? "bot.autoRelog.reconnect_always" : "bot.autoRelog.reconnect", msg); LogDebugToConsoleTranslated(String.IsNullOrEmpty(msg) ? "bot.autoRelog.reconnect_always" : "bot.autoRelog.reconnect", msg);
LogToConsoleTranslated("bot.autoRelog.wait", delay); LogToConsoleTranslated("bot.autoRelog.wait", delay);
System.Threading.Thread.Sleep(delay * 1000); System.Threading.Thread.Sleep(delay * 1000);

View file

@ -113,7 +113,7 @@ namespace MinecraftClient.ChatBots
public override void OnEntityMove(Entity entity) public override void OnEntityMove(Entity entity)
{ {
if (_updateCounter < (int)(Config.Update_Limit * 10)) if (_updateCounter < Settings.DoubleToTick(Config.Update_Limit))
return; return;
_updateCounter = 0; _updateCounter = 0;

View file

@ -39,7 +39,7 @@ namespace MinecraftClient.ChatBots
public override void Update() public override void Update()
{ {
count++; count++;
if (count == (int)(Config.Delay * 10)) if (count >= Settings.DoubleToTick(Config.Delay))
{ {
DateTime now = DateTime.Now; DateTime now = DateTime.Now;

View file

@ -26,7 +26,7 @@ namespace MinecraftClient.ChatBots
Trigger_On_First_Login: false, Trigger_On_First_Login: false,
Trigger_On_Login: false, Trigger_On_Login: false,
Trigger_On_Times: new(true, new TimeSpan[] { new(14, 00, 00) }), Trigger_On_Times: new(true, new TimeSpan[] { new(14, 00, 00) }),
Trigger_On_Interval: new(true, 10, 20), Trigger_On_Interval: new(true, 3.6, 4.8),
Action: "send /hello" Action: "send /hello"
), ),
new TaskConfig( new TaskConfig(
@ -43,8 +43,8 @@ namespace MinecraftClient.ChatBots
{ {
foreach (TaskConfig task in TaskList) foreach (TaskConfig task in TaskList)
{ {
task.Trigger_On_Interval.MinTime = Math.Max(1, task.Trigger_On_Interval.MinTime); task.Trigger_On_Interval.MinTime = Math.Max(0.1, task.Trigger_On_Interval.MinTime);
task.Trigger_On_Interval.MaxTime = Math.Max(1, task.Trigger_On_Interval.MaxTime); task.Trigger_On_Interval.MaxTime = Math.Max(0.1, task.Trigger_On_Interval.MaxTime);
if (task.Trigger_On_Interval.MinTime > task.Trigger_On_Interval.MaxTime) if (task.Trigger_On_Interval.MinTime > task.Trigger_On_Interval.MaxTime)
(task.Trigger_On_Interval.MinTime, task.Trigger_On_Interval.MaxTime) = (task.Trigger_On_Interval.MaxTime, task.Trigger_On_Interval.MinTime); (task.Trigger_On_Interval.MinTime, task.Trigger_On_Interval.MaxTime) = (task.Trigger_On_Interval.MaxTime, task.Trigger_On_Interval.MinTime);
@ -59,7 +59,7 @@ namespace MinecraftClient.ChatBots
{ {
if (Settings.Config.Logging.DebugMessages) if (Settings.Config.Logging.DebugMessages)
LogToConsole(BotName, Translations.TryGet("bot.scriptScheduler.loaded_task", Task2String(task))); LogToConsole(BotName, Translations.TryGet("bot.scriptScheduler.loaded_task", Task2String(task)));
task.Trigger_On_Interval_Countdown = task.Trigger_On_Interval.MinTime; //Init countdown for interval task.Trigger_On_Interval_Countdown = Settings.DoubleToTick(task.Trigger_On_Interval.MinTime); //Init countdown for interval
} }
else else
{ {
@ -130,27 +130,27 @@ namespace MinecraftClient.ChatBots
public struct TriggerOnIntervalConfig public struct TriggerOnIntervalConfig
{ {
public bool Enable = false; public bool Enable = false;
public int MinTime, MaxTime; public double MinTime, MaxTime;
public TriggerOnIntervalConfig(int value) public TriggerOnIntervalConfig(double value)
{ {
this.Enable = true; this.Enable = true;
MinTime = MaxTime = value; MinTime = MaxTime = value;
} }
public TriggerOnIntervalConfig(bool Enable, int value) public TriggerOnIntervalConfig(bool Enable, double value)
{ {
this.Enable = Enable; this.Enable = Enable;
MinTime = MaxTime = value; MinTime = MaxTime = value;
} }
public TriggerOnIntervalConfig(int min, int max) public TriggerOnIntervalConfig(double min, double max)
{ {
this.MinTime = min; this.MinTime = min;
this.MaxTime = max; this.MaxTime = max;
} }
public TriggerOnIntervalConfig(bool Enable, int min, int max) public TriggerOnIntervalConfig(bool Enable, double min, double max)
{ {
this.Enable = Enable; this.Enable = Enable;
this.MinTime = min; this.MinTime = min;
@ -199,16 +199,6 @@ namespace MinecraftClient.ChatBots
task.Trigger_On_Time_Already_Triggered = false; task.Trigger_On_Time_Already_Triggered = false;
} }
if (task.Trigger_On_Interval.Enable)
{
if (task.Trigger_On_Interval_Countdown == 0)
{
task.Trigger_On_Interval_Countdown = random.Next(task.Trigger_On_Interval.MinTime, task.Trigger_On_Interval.MaxTime);
LogDebugToConsoleTranslated("bot.scriptScheduler.running_inverval", task.Action);
PerformInternalCommand(task.Action);
}
else task.Trigger_On_Interval_Countdown--;
}
} }
} }
else else
@ -227,6 +217,22 @@ namespace MinecraftClient.ChatBots
} }
} }
else verifytasks_timeleft--; else verifytasks_timeleft--;
foreach (TaskConfig task in Config.TaskList)
{
if (task.Trigger_On_Interval.Enable)
{
if (task.Trigger_On_Interval_Countdown == 0)
{
task.Trigger_On_Interval_Countdown = random.Next(
Settings.DoubleToTick(task.Trigger_On_Interval.MinTime), Settings.DoubleToTick(task.Trigger_On_Interval.MaxTime)
);
LogDebugToConsoleTranslated("bot.scriptScheduler.running_inverval", task.Action);
PerformInternalCommand(task.Action);
}
else task.Trigger_On_Interval_Countdown--;
}
}
} }
public override bool OnDisconnect(DisconnectReason reason, string message) public override bool OnDisconnect(DisconnectReason reason, string message)

View file

@ -252,25 +252,25 @@ namespace MinecraftClient
/// </summary> /// </summary>
private void RegisterBots(bool reload = false) private void RegisterBots(bool reload = false)
{ {
if (Config.ChatBot.AntiAFK.Enabled) { BotLoad(new AntiAFK()); }
if (Config.ChatBot.HangmanGame.Enabled) { BotLoad(new HangmanGame()); }
if (Config.ChatBot.Alerts.Enabled) { BotLoad(new Alerts()); } if (Config.ChatBot.Alerts.Enabled) { BotLoad(new Alerts()); }
if (Config.ChatBot.ChatLog.Enabled) { BotLoad(new ChatLog()); } if (Config.ChatBot.AntiAFK.Enabled) { BotLoad(new AntiAFK()); }
if (Config.ChatBot.PlayerListLogger.Enabled) { BotLoad(new PlayerListLogger()); }
if (Config.ChatBot.AutoRelog.Enabled) { BotLoad(new AutoRelog()); }
if (Config.ChatBot.ScriptScheduler.Enabled) { BotLoad(new ScriptScheduler()); }
if (Config.ChatBot.RemoteControl.Enabled) { BotLoad(new RemoteControl()); }
if (Config.ChatBot.AutoRespond.Enabled) { BotLoad(new AutoRespond()); }
if (Config.ChatBot.AutoAttack.Enabled) { BotLoad(new AutoAttack()); } if (Config.ChatBot.AutoAttack.Enabled) { BotLoad(new AutoAttack()); }
if (Config.ChatBot.AutoFishing.Enabled) { BotLoad(new AutoFishing()); }
if (Config.ChatBot.AutoEat.Enabled) { BotLoad(new AutoEat()); }
if (Config.ChatBot.Mailer.Enabled) { BotLoad(new Mailer()); }
if (Config.ChatBot.AutoCraft.Enabled) { BotLoad(new AutoCraft()); } if (Config.ChatBot.AutoCraft.Enabled) { BotLoad(new AutoCraft()); }
if (Config.ChatBot.AutoDig.Enabled) { BotLoad(new AutoDig()); }
if (Config.ChatBot.AutoDrop.Enabled) { BotLoad(new AutoDrop()); } if (Config.ChatBot.AutoDrop.Enabled) { BotLoad(new AutoDrop()); }
if (Config.ChatBot.ReplayCapture.Enabled && reload) { BotLoad(new ReplayCapture()); } if (Config.ChatBot.AutoEat.Enabled) { BotLoad(new AutoEat()); }
if (Config.ChatBot.AutoFishing.Enabled) { BotLoad(new AutoFishing()); }
if (Config.ChatBot.AutoRelog.Enabled) { BotLoad(new AutoRelog()); }
if (Config.ChatBot.AutoRespond.Enabled) { BotLoad(new AutoRespond()); }
if (Config.ChatBot.ChatLog.Enabled) { BotLoad(new ChatLog()); }
if (Config.ChatBot.FollowPlayer.Enabled) { BotLoad(new FollowPlayer()); } if (Config.ChatBot.FollowPlayer.Enabled) { BotLoad(new FollowPlayer()); }
if (Config.ChatBot.HangmanGame.Enabled) { BotLoad(new HangmanGame()); }
if (Config.ChatBot.Mailer.Enabled) { BotLoad(new Mailer()); }
if (Config.ChatBot.Map.Enabled) { BotLoad(new Map()); } if (Config.ChatBot.Map.Enabled) { BotLoad(new Map()); }
if (Config.ChatBot.PlayerListLogger.Enabled) { BotLoad(new PlayerListLogger()); }
if (Config.ChatBot.RemoteControl.Enabled) { BotLoad(new RemoteControl()); }
if (Config.ChatBot.ReplayCapture.Enabled && reload) { BotLoad(new ReplayCapture()); }
if (Config.ChatBot.ScriptScheduler.Enabled) { BotLoad(new ScriptScheduler()); }
//Add your ChatBot here by uncommenting and adapting //Add your ChatBot here by uncommenting and adapting
//BotLoad(new ChatBots.YourBot()); //BotLoad(new ChatBots.YourBot());
} }
@ -3293,6 +3293,17 @@ namespace MinecraftClient
} }
} }
/// <summary>
/// Called when a block is changed.
/// </summary>
/// <param name="location">The location of the block.</param>
/// <param name="block">The block</param>
public void OnBlockChange(Location location, Block block)
{
world.SetBlock(location, block);
DispatchBotEvent(bot => bot.OnBlockChange(location, block));
}
#endregion #endregion
} }
} }

View file

@ -976,18 +976,20 @@ namespace MinecraftClient.Protocol.Handlers
int blocksSize = dataTypes.ReadNextVarInt(packetData); int blocksSize = dataTypes.ReadNextVarInt(packetData);
for (int i = 0; i < blocksSize; i++) for (int i = 0; i < blocksSize; i++)
{ {
ulong block = (ulong)dataTypes.ReadNextVarLong(packetData); ulong chunkSectionPosition = (ulong)dataTypes.ReadNextVarLong(packetData);
int blockId = (int)(block >> 12); int blockId = (int)(chunkSectionPosition >> 12);
int localX = (int)((block >> 8) & 0x0F); int localX = (int)((chunkSectionPosition >> 8) & 0x0F);
int localZ = (int)((block >> 4) & 0x0F); int localZ = (int)((chunkSectionPosition >> 4) & 0x0F);
int localY = (int)(block & 0x0F); int localY = (int)(chunkSectionPosition & 0x0F);
Block b = new((ushort)blockId); Block block = new((ushort)blockId);
int blockX = (sectionX * 16) + localX; int blockX = (sectionX * 16) + localX;
int blockY = (sectionY * 16) + localY; int blockY = (sectionY * 16) + localY;
int blockZ = (sectionZ * 16) + localZ; int blockZ = (sectionZ * 16) + localZ;
var l = new Location(blockX, blockY, blockZ);
handler.GetWorld().SetBlock(l, b); Location location = new(blockX, blockY, blockZ);
handler.OnBlockChange(location, block);
} }
} }
else else
@ -1019,8 +1021,10 @@ namespace MinecraftClient.Protocol.Handlers
int blockX = locationXZ >> 4; int blockX = locationXZ >> 4;
int blockZ = locationXZ & 0x0F; int blockZ = locationXZ & 0x0F;
Location location = new(chunkX, chunkZ, blockX, blockY, blockZ);
Block block = new(blockIdMeta); Block block = new(blockIdMeta);
handler.GetWorld().SetBlock(new Location(chunkX, chunkZ, blockX, blockY, blockZ), block); handler.OnBlockChange(location, block);
} }
} }
} }
@ -1050,11 +1054,16 @@ namespace MinecraftClient.Protocol.Handlers
int blockZ = dataTypes.ReadNextInt(packetData); int blockZ = dataTypes.ReadNextInt(packetData);
short blockId = (short)dataTypes.ReadNextVarInt(packetData); short blockId = (short)dataTypes.ReadNextVarInt(packetData);
byte blockMeta = dataTypes.ReadNextByte(packetData); byte blockMeta = dataTypes.ReadNextByte(packetData);
handler.GetWorld().SetBlock(new Location(blockX, blockY, blockZ), new Block(blockId, blockMeta));
Location location = new(blockX, blockY, blockZ);
Block block = new(blockId, blockMeta);
handler.OnBlockChange(location, block);
} }
else else
{ {
handler.GetWorld().SetBlock(dataTypes.ReadNextLocation(packetData), new Block((ushort)dataTypes.ReadNextVarInt(packetData))); Location location = dataTypes.ReadNextLocation(packetData);
Block block = new((ushort)dataTypes.ReadNextVarInt(packetData));
handler.OnBlockChange(location, block);
} }
} }
break; break;

View file

@ -432,5 +432,12 @@ namespace MinecraftClient.Protocol
/// <param name="reason">Event type</param> /// <param name="reason">Event type</param>
/// <param name="value">Depends on Reason</param> /// <param name="value">Depends on Reason</param>
public void OnGameEvent(byte reason, float value); public void OnGameEvent(byte reason, float value);
/// <summary>
/// Called when a block is changed.
/// </summary>
/// <param name="location">The location of the block.</param>
/// <param name="block">The block</param>
public void OnBlockChange(Location location, Block block);
} }
} }

View file

@ -495,6 +495,18 @@ bot.autoCraft.debug.no_config=No config found. Writing a new one.
bot.autocraft.invaild_slots=The number of slots does not match and has been adjusted automatically. bot.autocraft.invaild_slots=The number of slots does not match and has been adjusted automatically.
bot.autocraft.invaild_invaild_result=Invalid result item! bot.autocraft.invaild_invaild_result=Invalid result item!
# AutoDig
bot.autodig.start_delay=Digging will start in {0:0.0} second(s).
bot.autodig.dig_timeout=Digging block timeout, retry.
bot.autodig.not_allow=The block currently pointed to is not in the allowed list.
bot.autodig.cmd=Auto-digging ChatBot command
bot.autodig.available_cmd=Available commands: {0}. Use /digbot help <cmd name> for more information.
bot.autodig.start=Automatic digging has started.
bot.autodig.stop=Auto-digging has been stopped.
bot.autodig.help.start=Start the automatic digging bot.
bot.autodig.help.stop=Deactivate the automatic digging bot.
bot.autodig.help.help=Get the command description. Usage: /digbot help <command name>
# AutoDrop # AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot command bot.autoDrop.cmd=AutoDrop ChatBot command
bot.autoDrop.alias=AutoDrop ChatBot command alias bot.autoDrop.alias=AutoDrop ChatBot command alias
@ -786,6 +798,18 @@ config.ChatBot.AutoCraft.CraftingTable=Location of the crafting table if you int
config.ChatBot.AutoCraft.OnFailure=What to do on crafting failure, "abort" or "wait". config.ChatBot.AutoCraft.OnFailure=What to do on crafting failure, "abort" or "wait".
config.ChatBot.AutoCraft.Recipes=Recipes.Name: The name can be whatever you like and it is used to represent the recipe.\n# Recipes.Type: crafting table type: "player" or "table"\n# Recipes.Result: the resulting item\n# Recipes.Slots: All slots, counting from left to right, top to bottom. Please fill in "Null" for empty slots.\n# For the naming of the items, please see:\n# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs config.ChatBot.AutoCraft.Recipes=Recipes.Name: The name can be whatever you like and it is used to represent the recipe.\n# Recipes.Type: crafting table type: "player" or "table"\n# Recipes.Result: the resulting item\n# Recipes.Slots: All slots, counting from left to right, top to bottom. Please fill in "Null" for empty slots.\n# For the naming of the items, please see:\n# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
# AutoDig
config.ChatBot.AutoDig=Auto-digging blocks.\n# You can use "/digbot start" and "/digbot stop" to control the start and stop of AutoDig.\n# Since MCC does not yet support accurate calculation of the collision volume of blocks, all blocks are considered as complete cubes when obtaining the position of the lookahead.\n# For the naming of the block, please see https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Mapping/Material.cs
config.ChatBot.AutoDig.Auto_Tool_Switch=Automatically switch to the appropriate tool.
config.ChatBot.AutoDig.Durability_Limit=Will not use tools with less durability than this. Set to zero to disable this feature.
config.ChatBot.AutoDig.Drop_Low_Durability_Tools=Whether to drop the current tool when its durability is too low.
config.ChatBot.AutoDig.Mode="lookat", "fixedpos" or "both". Digging the block being looked at, the block in a fixed position, or the block that needs to be all met.
config.ChatBot.AutoDig.Locations=The position of the blocks when using "fixedpos" or "both" mode.
config.ChatBot.AutoDig.Auto_Start_Delay=How many seconds to wait after entering the game to start digging automatically, set to -1 to disable automatic start.
config.ChatBot.AutoDig.Dig_Timeout=Mining a block for more than "Dig_Timeout" seconds will be considered a timeout.
config.ChatBot.AutoDig.Log_Block_Dig=Whether to output logs when digging blocks.
config.ChatBot.AutoDig.List_Type=Wether to treat the blocks list as a "whitelist" or as a "blacklist".
# ChatBot.AutoDrop # ChatBot.AutoDrop
config.ChatBot.AutoDrop=Automatically drop items in inventory\n# You need to enable Inventory Handling to use this bot\n# See this file for an up-to-date list of item types you can use with this bot:\n# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs config.ChatBot.AutoDrop=Automatically drop items in inventory\n# You need to enable Inventory Handling to use this bot\n# See this file for an up-to-date list of item types you can use with this bot:\n# https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
config.ChatBot.AutoDrop.Mode="include", "exclude" or "everything". Include: drop item IN the list. Exclude: drop item NOT IN the list config.ChatBot.AutoDrop.Mode="include", "exclude" or "everything". Include: drop item IN the list. Exclude: drop item NOT IN the list

View file

@ -478,7 +478,7 @@ bot.autoCraft.help.reload=重新加载配置文件。
bot.autoCraft.help.resetcfg=将默认示例配置写入默认位置。 bot.autoCraft.help.resetcfg=将默认示例配置写入默认位置。
bot.autoCraft.help.start=开始制作。用法:/autocraft start <配方名称> bot.autoCraft.help.start=开始制作。用法:/autocraft start <配方名称>
bot.autoCraft.help.stop=停止当前正在进行的制作过程 bot.autoCraft.help.stop=停止当前正在进行的制作过程
bot.autoCraft.help.help=获取命令描述。用法: /autocraft help <命令名> bot.autoCraft.help.help=获取命令描述。用法:/autocraft help <命令名>
bot.autoCraft.loaded=已成功加载 bot.autoCraft.loaded=已成功加载
bot.autoCraft.start=AutoCraft启动中{0} bot.autoCraft.start=AutoCraft启动中{0}
bot.autoCraft.start_fail=无法启动AutoCraft。请检查用于制作{0}的可用材料 bot.autoCraft.start_fail=无法启动AutoCraft。请检查用于制作{0}的可用材料
@ -495,6 +495,18 @@ bot.autoCraft.debug.no_config=找不到配置。请新建一个。
bot.autocraft.invaild_slots=配方的物品数量不匹配,已自动调整。 bot.autocraft.invaild_slots=配方的物品数量不匹配,已自动调整。
bot.autocraft.invaild_invaild_result=无效的输出物品! bot.autocraft.invaild_invaild_result=无效的输出物品!
# AutoDig
bot.autodig.start_delay=将在 {0:0.0} 秒后开始自动挖掘。
bot.autodig.dig_timeout=挖掘方块超时,重试。
bot.autodig.not_allow=当前所看向的方块不在允许挖掘列表中。
bot.autodig.cmd=自动挖掘 ChatBot 命令
bot.autodig.available_cmd=可用命令:{0}。可使用 /digbot help <命令名> 了解更多信息。
bot.autodig.start=开始自动挖掘。
bot.autodig.stop=停止自动挖掘。
bot.autodig.help.start=开始运行自动挖掘。
bot.autodig.help.stop=停止运行自动挖掘。
bot.autodig.help.help=获取命令描述。用法:/digbot help <命令名>
# AutoDrop # AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot命令 bot.autoDrop.cmd=AutoDrop ChatBot命令
bot.autoDrop.alias=AutoDrop ChatBot命令别名 bot.autoDrop.alias=AutoDrop ChatBot命令别名
@ -786,6 +798,18 @@ config.ChatBot.AutoCraft.CraftingTable=如果你打算使用工作台,请填
config.ChatBot.AutoCraft.OnFailure=合成失败时应该怎么处理,"abort"(中止)或 "wait"(等待)。 config.ChatBot.AutoCraft.OnFailure=合成失败时应该怎么处理,"abort"(中止)或 "wait"(等待)。
config.ChatBot.AutoCraft.Recipes=Recipes.Name给该配方起一个独一无二的名字。不能包含空白字符Recipes.Type合成类型"player"背包2x2或 "table"工作台3x3\n# Recipes.Result合成的目标物品\n# Recipes.Slots合成的物品摆放方式以从左到右、从上到下的格式填写。需留空请填写"Null"。\n# 最新的物品命名请看https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs config.ChatBot.AutoCraft.Recipes=Recipes.Name给该配方起一个独一无二的名字。不能包含空白字符Recipes.Type合成类型"player"背包2x2或 "table"工作台3x3\n# Recipes.Result合成的目标物品\n# Recipes.Slots合成的物品摆放方式以从左到右、从上到下的格式填写。需留空请填写"Null"。\n# 最新的物品命名请看https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
# AutoDig
config.ChatBot.AutoDig=自动挖掘方块。\n# 你可以使用 "/digbot start" 和 "/digbot stop" 指令来控制 AutoDig 的启停。\n# 由于MCC目前还不支持精确计算方块的碰撞体积在获取看向的方块时视线上所有的方块都被看作是完整的立方体。\n# 查询方块的名字,请访问 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Mapping/Material.cs
config.ChatBot.AutoDig.Auto_Tool_Switch=自动切换到合适的工具。
config.ChatBot.AutoDig.Durability_Limit=不会使用低于此耐久度的工具。(需要启用库存处理)
config.ChatBot.AutoDig.Drop_Low_Durability_Tools=在当前使用的工具耐久度过低后,是否丢掉它。
config.ChatBot.AutoDig.Mode="lookat""fixedpos" 或 "both"。挖掘看向的方块还是固定位置的方块,或者是两个条件都满足的方块。
config.ChatBot.AutoDig.Locations=使用 "fixedpos" 或 "both" 模式时,方块的坐标。
config.ChatBot.AutoDig.Auto_Start_Delay=进入游戏后等待多少秒后开始自动挖掘,设置为-1禁用自动开始。
config.ChatBot.AutoDig.Dig_Timeout=若挖掘一个方块用时超过这个值,将会重新获取目标进行挖掘。
config.ChatBot.AutoDig.Log_Block_Dig=是否输出挖掘方块的相关信息。
config.ChatBot.AutoDig.List_Type=将方块列表作为 "whitelist"(白名单)还是 "blacklist"(黑名单)。
# ChatBot.AutoDrop # ChatBot.AutoDrop
config.ChatBot.AutoDrop=自动从背包/库存中丢弃指定的物品\n# 你需要启用库存处理来使用这个功能。\n# 可用物品请看 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs config.ChatBot.AutoDrop=自动从背包/库存中丢弃指定的物品\n# 你需要启用库存处理来使用这个功能。\n# 可用物品请看 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
config.ChatBot.AutoDrop.Mode="include"(丢弃列表中的物品),"exclude"(丢弃列表外的所有物品) 或 "everything"(丢弃所有物品) config.ChatBot.AutoDrop.Mode="include"(丢弃列表中的物品),"exclude"(丢弃列表外的所有物品) 或 "everything"(丢弃所有物品)

View file

@ -495,6 +495,18 @@ bot.autoCraft.debug.no_config=找不到配置。請新建一個。
bot.autocraft.invaild_slots=配方的物品數量不匹配,已自動調整。 bot.autocraft.invaild_slots=配方的物品數量不匹配,已自動調整。
bot.autocraft.invaild_invaild_result=無效的輸出物品! bot.autocraft.invaild_invaild_result=無效的輸出物品!
# AutoDig
bot.autodig.start_delay=將在 {0:0.0} 秒後開始自動挖掘。
bot.autodig.dig_timeout=挖掘方塊超時,重試。
bot.autodig.not_allow=當前所看向的方塊不在允許挖掘列表中。
bot.autodig.cmd=自動挖掘 ChatBot 命令
bot.autodig.available_cmd=可用命令:{0}。可使用 /digbot help <命令名> 瞭解更多資訊。
bot.autodig.start=開始自動挖掘。
bot.autodig.stop=停止自動挖掘。
bot.autodig.help.start=開始執行自動挖掘。
bot.autodig.help.stop=停止執行自動挖掘。
bot.autodig.help.help=獲取命令描述。用法:/digbot help <命令名>
# AutoDrop # AutoDrop
bot.autoDrop.cmd=AutoDrop ChatBot命令 bot.autoDrop.cmd=AutoDrop ChatBot命令
bot.autoDrop.alias=AutoDrop ChatBot命令別名 bot.autoDrop.alias=AutoDrop ChatBot命令別名
@ -786,6 +798,18 @@ config.ChatBot.AutoCraft.CraftingTable=如果你打算使用工作臺,請填
config.ChatBot.AutoCraft.OnFailure=合成失敗時應該怎麼處理,"abort"(中止)或 "wait"(等待)。 config.ChatBot.AutoCraft.OnFailure=合成失敗時應該怎麼處理,"abort"(中止)或 "wait"(等待)。
config.ChatBot.AutoCraft.Recipes=Recipes.Name給該配方起一個獨一無二的名字。不能包含空白字元Recipes.Type合成型別"player"揹包2x2或 "table"工作臺3x3\n# Recipes.Result合成的目標物品\n# Recipes.Slots合成的物品擺放方式以從左到右、從上到下的格式填寫。需留空請填寫"Null"。\n# 最新的物品命名請看https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs config.ChatBot.AutoCraft.Recipes=Recipes.Name給該配方起一個獨一無二的名字。不能包含空白字元Recipes.Type合成型別"player"揹包2x2或 "table"工作臺3x3\n# Recipes.Result合成的目標物品\n# Recipes.Slots合成的物品擺放方式以從左到右、從上到下的格式填寫。需留空請填寫"Null"。\n# 最新的物品命名請看https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
# AutoDig
config.ChatBot.AutoDig=自動挖掘方塊。\n# 你可以使用 "/digbot start" 和 "/digbot stop" 指令來控制 AutoDig 的啟停。\n# 由於MCC目前還不支援精確計算方塊的碰撞體積在獲取看向的方塊時視線上所有的方塊都被看作是完整的立方體。\n# 查詢方塊的名字,請訪問 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Mapping/Material.cs
config.ChatBot.AutoDig.Auto_Tool_Switch=自動切換到合適的工具。
config.ChatBot.AutoDig.Durability_Limit=不會使用低於此耐久度的工具。(需要啟用庫存處理)
config.ChatBot.AutoDig.Drop_Low_Durability_Tools=在當前使用的工具耐久度過低後,是否丟掉它。
config.ChatBot.AutoDig.Mode="lookat""fixedpos" 或 "both"。挖掘看向的方塊還是固定位置的方塊,或者是兩個條件都滿足的方塊。
config.ChatBot.AutoDig.Locations=使用 "fixedpos" 或 "both" 模式時,方塊的座標。
config.ChatBot.AutoDig.Auto_Start_Delay=進入遊戲後等待多少秒後開始自動挖掘,設定為-1禁用自動開始。
config.ChatBot.AutoDig.Dig_Timeout=若挖掘一個方塊用時超過這個值,將會重新獲取目標進行挖掘。
config.ChatBot.AutoDig.Log_Block_Dig=是否輸出挖掘方塊的相關資訊。
config.ChatBot.AutoDig.List_Type=將方塊列表作為 "whitelist"(白名單)還是 "blacklist"(黑名單)。
# ChatBot.AutoDrop # ChatBot.AutoDrop
config.ChatBot.AutoDrop=自動從揹包/庫存中丟棄指定的物品\n# 你需要啟用庫存處理來使用這個功能。\n# 可用物品請看 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs config.ChatBot.AutoDrop=自動從揹包/庫存中丟棄指定的物品\n# 你需要啟用庫存處理來使用這個功能。\n# 可用物品請看 https://github.com/MCCTeam/Minecraft-Console-Client/blob/master/MinecraftClient/Inventory/ItemType.cs
config.ChatBot.AutoDrop.Mode="include"(丟棄列表中的物品),"exclude"(丟棄列表外的所有物品) 或 "everything"(丟棄所有物品) config.ChatBot.AutoDrop.Mode="include"(丟棄列表中的物品),"exclude"(丟棄列表外的所有物品) 或 "everything"(丟棄所有物品)

View file

@ -426,6 +426,14 @@ namespace MinecraftClient
/// <param name="level"></param> /// <param name="level"></param>
public virtual void OnThunderLevelChange(float level) { } public virtual void OnThunderLevelChange(float level) { }
/// <summary>
/// Called when a block is changed.
/// </summary>
/// <param name="location">The location of the block.</param>
/// <param name="block">The block</param>
public virtual void OnBlockChange(Location location, Block block) { }
/* =================================================================== */ /* =================================================================== */
/* ToolBox - Methods below might be useful while creating your bot. */ /* ToolBox - Methods below might be useful while creating your bot. */
/* You should not need to interact with other classes of the program. */ /* You should not need to interact with other classes of the program. */

View file

@ -986,6 +986,13 @@ namespace MinecraftClient
set { ChatBots.AutoCraft.Config = value; ChatBots.AutoCraft.Config.OnSettingUpdate(); } set { ChatBots.AutoCraft.Config = value; ChatBots.AutoCraft.Config.OnSettingUpdate(); }
} }
[TomlPrecedingComment("$config.ChatBot.AutoDig$")]
public ChatBots.AutoDig.Configs AutoDig
{
get { return ChatBots.AutoDig.Config; }
set { ChatBots.AutoDig.Config = value; ChatBots.AutoDig.Config.OnSettingUpdate(); }
}
[TomlPrecedingComment("$config.ChatBot.AutoDrop$")] [TomlPrecedingComment("$config.ChatBot.AutoDrop$")]
public ChatBots.AutoDrop.Configs AutoDrop public ChatBots.AutoDrop.Configs AutoDrop
{ {
@ -1170,6 +1177,12 @@ namespace MinecraftClient
else else
return false; return false;
} }
public static int DoubleToTick(double time)
{
time = Math.Min(int.MaxValue / 10, time);
return (int)Math.Round(time * 10);
}
} }
public static class InternalCmdCharTypeExtensions public static class InternalCmdCharTypeExtensions

View file

@ -69,11 +69,14 @@ namespace MinecraftClient.WinAPI
} }
catch (AggregateException ae) catch (AggregateException ae)
{ {
bool needRevert = false;
foreach (var ex in ae.InnerExceptions) foreach (var ex in ae.InnerExceptions)
{ {
if (ex is HttpRequestException) //Skin not found? Reset to default icon if (ex is HttpRequestException || ex is TaskCanceledException) //Skin not found? Reset to default icon
RevertToMCCIcon(); needRevert = true;
} }
if (needRevert)
RevertToMCCIcon();
} }
catch (HttpRequestException) //Skin not found? Reset to default icon catch (HttpRequestException) //Skin not found? Reset to default icon
{ {