From 50dd5a3ba3602ec0f44d0a6725b33682c4d0c246 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sun, 15 Jan 2023 20:56:10 +0800 Subject: [PATCH] Support specifying the digging duration --- MinecraftClient/Commands/Dig.cs | 14 ++-- MinecraftClient/McClient.cs | 64 +++++++++++++++---- .../Translations/Translations.Designer.cs | 18 ++++++ .../Resources/Translations/Translations.resx | 6 ++ 4 files changed, 84 insertions(+), 18 deletions(-) diff --git a/MinecraftClient/Commands/Dig.cs b/MinecraftClient/Commands/Dig.cs index 3a30619a..3a00c44b 100644 --- a/MinecraftClient/Commands/Dig.cs +++ b/MinecraftClient/Commands/Dig.cs @@ -23,8 +23,12 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DigLookAt(r.Source)) + .Then(l => l.Argument("Duration", Arguments.Double()) + .Executes(r => DigLookAt(r.Source, Arguments.GetDouble(r, "Duration")))) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DigAt(r.Source, MccArguments.GetLocation(r, "Location")))) + .Executes(r => DigAt(r.Source, MccArguments.GetLocation(r, "Location"))) + .Then(l => l.Argument("Duration", Arguments.Double()) + .Executes(r => DigAt(r.Source, MccArguments.GetLocation(r, "Location"), Arguments.GetDouble(r, "Duration"))))) .Then(l => l.Literal("_help") .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) @@ -41,7 +45,7 @@ namespace MinecraftClient.Commands }); } - private int DigAt(CmdResult r, Location blockToBreak) + private int DigAt(CmdResult r, Location blockToBreak, double duration = 0) { McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) @@ -54,7 +58,7 @@ namespace MinecraftClient.Commands Block block = handler.GetWorld().GetBlock(blockToBreak); if (block.Type == Material.Air) return r.SetAndReturn(Status.Fail, Translations.cmd_dig_no_block); - else if (handler.DigBlock(blockToBreak)) + else if (handler.DigBlock(blockToBreak, duration: duration)) { blockToBreak = blockToBreak.ToCenter(); return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_dig_dig, blockToBreak.X, blockToBreak.Y, blockToBreak.Z, block.GetTypeString())); @@ -63,7 +67,7 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Fail, Translations.cmd_dig_fail); } - private int DigLookAt(CmdResult r) + private int DigLookAt(CmdResult r, double duration = 0) { McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) @@ -74,7 +78,7 @@ namespace MinecraftClient.Commands return r.SetAndReturn(Status.Fail, Translations.cmd_dig_too_far); else if (block.Type == Material.Air) return r.SetAndReturn(Status.Fail, Translations.cmd_dig_no_block); - else if (handler.DigBlock(blockLoc, lookAtBlock: false)) + else if (handler.DigBlock(blockLoc, lookAtBlock: false, duration: duration)) return r.SetAndReturn(Status.Done, string.Format(Translations.cmd_dig_dig, blockLoc.X, blockLoc.Y, blockLoc.Z, block.GetTypeString())); else return r.SetAndReturn(Status.Fail, Translations.cmd_dig_fail); diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 56eb4811..e61d2350 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -87,6 +87,10 @@ namespace MinecraftClient private int playerEntityID; + private object DigLock = new(); + private Tuple? LastDigPosition; + private int RemainingDiggingTime = 0; + // player health and hunger private float playerHealth; private int playerFoodSaturation; @@ -380,6 +384,22 @@ namespace MinecraftClient taskToRun(); } } + + lock (DigLock) + { + if (RemainingDiggingTime > 0) + { + if (--RemainingDiggingTime == 0 && LastDigPosition != null) + { + handler.SendPlayerDigging(2, LastDigPosition.Item1, LastDigPosition.Item2, sequenceId++); + Log.Info(string.Format(Translations.cmd_dig_end, LastDigPosition.Item1)); + } + else + { + DoAnimation((int)Hand.MainHand); + } + } + } } #region Connection Lost and Disconnect from Server @@ -1299,7 +1319,7 @@ namespace MinecraftClient /// TRUE if the item was successfully used public bool UseItemOnHand() { - return InvokeOnMainThread(() => handler.SendUseItem(0, sequenceId)); + return InvokeOnMainThread(() => handler.SendUseItem(0, sequenceId++)); } /// @@ -1308,7 +1328,7 @@ namespace MinecraftClient /// TRUE if the item was successfully used public bool UseItemOnLeftHand() { - return InvokeOnMainThread(() => handler.SendUseItem(1, sequenceId)); + return InvokeOnMainThread(() => handler.SendUseItem(1, sequenceId++)); } /// @@ -2193,7 +2213,7 @@ namespace MinecraftClient /// TRUE if successfully placed public bool PlaceBlock(Location location, Direction blockFace, Hand hand = Hand.MainHand) { - return InvokeOnMainThread(() => handler.SendPlayerBlockPlacement((int)hand, location, blockFace, sequenceId)); + return InvokeOnMainThread(() => handler.SendPlayerBlockPlacement((int)hand, location, blockFace, sequenceId++)); } /// @@ -2202,26 +2222,44 @@ namespace MinecraftClient /// Location of block to dig /// Also perform the "arm swing" animation /// Also look at the block before digging - public bool DigBlock(Location location, bool swingArms = true, bool lookAtBlock = true) + public bool DigBlock(Location location, bool swingArms = true, bool lookAtBlock = true, double duration = 0) { if (!GetTerrainEnabled()) return false; if (InvokeRequired) - return InvokeOnMainThread(() => DigBlock(location, swingArms, lookAtBlock)); + return InvokeOnMainThread(() => DigBlock(location, swingArms, lookAtBlock, duration)); // TODO select best face from current player location Direction blockFace = Direction.Down; - // Look at block before attempting to break it - if (lookAtBlock) - UpdateLocation(GetCurrentLocation(), location); + lock (DigLock) + { + if (RemainingDiggingTime > 0 && LastDigPosition != null) + { + handler.SendPlayerDigging(1, LastDigPosition.Item1, LastDigPosition.Item2, sequenceId++); + Log.Info(string.Format(Translations.cmd_dig_cancel, LastDigPosition.Item1)); + } - // 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, sequenceId) - && (!swingArms || DoAnimation((int)Hand.MainHand)) - && handler.SendPlayerDigging(2, location, blockFace, sequenceId); + // Look at block before attempting to break it + if (lookAtBlock) + 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 + bool result = handler.SendPlayerDigging(0, location, blockFace, sequenceId++) + && (!swingArms || DoAnimation((int)Hand.MainHand)); + + if (duration <= 0) + result &= handler.SendPlayerDigging(2, location, blockFace, sequenceId++); + else + { + LastDigPosition = new(location, blockFace); + RemainingDiggingTime = Settings.DoubleToTick(duration); + } + + return result; + } } /// diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index 9c1b8d84..a0ca3082 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -2704,6 +2704,15 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Cancel mining the block located at {0}.. + /// + internal static string cmd_dig_cancel { + get { + return ResourceManager.GetString("cmd.dig.cancel", resourceCulture); + } + } + /// /// Looks up a localized string similar to Attempt to break a block. /// @@ -2722,6 +2731,15 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Mining of the block located at {0} ends.. + /// + internal static string cmd_dig_end { + get { + return ResourceManager.GetString("cmd.dig.end", resourceCulture); + } + } + /// /// Looks up a localized string similar to Failed to start digging block.. /// diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index 73e81493..120249c5 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -2028,4 +2028,10 @@ Logging in... Connected to proxy {0}:{1} + + Mining of the block located at {0} ends. + + + Cancel mining the block located at {0}. + \ No newline at end of file