From 04a975d0111bc26dc8ab700708d57db442c350a8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 2 Jun 2026 07:57:13 +0000 Subject: [PATCH] fix: support offhand food useitem fallback --- MinecraftClient/Commands/UseItem.cs | 52 +++++++++++++++++++++++------ docs/guide/usage.md | 12 +++++++ 2 files changed, 54 insertions(+), 10 deletions(-) diff --git a/MinecraftClient/Commands/UseItem.cs b/MinecraftClient/Commands/UseItem.cs index 40993c7a..70ad0003 100644 --- a/MinecraftClient/Commands/UseItem.cs +++ b/MinecraftClient/Commands/UseItem.cs @@ -10,7 +10,7 @@ namespace MinecraftClient.Commands class UseItem : Command { public override string CmdName { get { return "useitem"; } } - public override string CmdUsage { get { return "useitem [x] [y] [z]"; } } + public override string CmdUsage { get { return "useitem [mainhand|offhand] | useitem [x] [y] [z] [mainhand|offhand]"; } } public override string CmdDesc { get { return Translations.cmd_useitem_desc; } } public override void RegisterCommand(CommandDispatcher dispatcher) @@ -23,8 +23,16 @@ namespace MinecraftClient.Commands dispatcher.Register(l => l.Literal(CmdName) .Executes(r => DoUseItem(r.Source)) + .Then(l => l.Literal("mainhand") + .Executes(r => DoUseItem(r.Source, Hand.MainHand))) + .Then(l => l.Literal("offhand") + .Executes(r => DoUseItem(r.Source, Hand.OffHand))) .Then(l => l.Argument("Location", MccArguments.Location()) - .Executes(r => DoUseItemAtLocation(r.Source, MccArguments.GetLocation(r, "Location")))) + .Executes(r => DoUseItemAtLocation(r.Source, MccArguments.GetLocation(r, "Location"), Hand.MainHand)) + .Then(l => l.Literal("mainhand") + .Executes(r => DoUseItemAtLocation(r.Source, MccArguments.GetLocation(r, "Location"), Hand.MainHand))) + .Then(l => l.Literal("offhand") + .Executes(r => DoUseItemAtLocation(r.Source, MccArguments.GetLocation(r, "Location"), Hand.OffHand)))) .Then(l => l.Literal("_help") .Executes(r => GetUsage(r.Source, string.Empty)) .Redirect(dispatcher.GetRoot().GetChild("help").GetChild(CmdName))) @@ -41,29 +49,53 @@ namespace MinecraftClient.Commands }); } - private int DoUseItem(CmdResult r) + private static bool ShouldUseOffhandFood(McClient handler) + { + Container? inventory = handler.GetInventory(0); + if (inventory is null) + return false; + + if (!inventory.Items.TryGetValue(45, out Item? offhandItem) + || offhandItem.IsEmpty + || !offhandItem.Type.IsFood()) + return false; + + int mainHandSlot = 36 + handler.GetCurrentSlot(); + return !inventory.Items.TryGetValue(mainHandSlot, out Item? mainHandItem) + || mainHandItem.IsEmpty + || !mainHandItem.Type.IsFood(); + } + + private int DoUseItem(CmdResult r, Hand? requestedHand = null) { McClient handler = CmdResult.currentHandler!; if (!handler.GetInventoryEnabled()) return r.SetAndReturn(Status.FailNeedInventory); - if (handler.GetTerrainEnabled()) + Hand hand = requestedHand ?? (ShouldUseOffhandFood(handler) ? Hand.OffHand : Hand.MainHand); + bool useOffhandFood = !requestedHand.HasValue && hand == Hand.OffHand; + + if (!useOffhandFood && handler.GetTerrainEnabled()) { const double maxDistance = 4.5; var raycast = RaycastHelper.RaycastBlock(handler, maxDistance, false); if (raycast.Item1 && raycast.Item3.Type != Material.Air) { - handler.PlaceBlock(raycast.Item2, Direction.Up, lookAtBlock: true); - handler.DoAnimation((int)Hand.MainHand); + handler.PlaceBlock(raycast.Item2, Direction.Up, hand, lookAtBlock: true); + handler.DoAnimation((int)hand); return r.SetAndReturn(Status.Done, Translations.cmd_useitem_use); } } - handler.UseItemOnHand(); + if (hand == Hand.OffHand) + handler.UseItemOnLeftHand(); + else + handler.UseItemOnHand(); + return r.SetAndReturn(Status.Done, Translations.cmd_useitem_use); } - private int DoUseItemAtLocation(CmdResult r, Location block) + private int DoUseItemAtLocation(CmdResult r, Location block, Hand hand) { McClient handler = CmdResult.currentHandler!; if (!handler.GetTerrainEnabled()) @@ -71,8 +103,8 @@ namespace MinecraftClient.Commands Location current = handler.GetCurrentLocation(); block = block.ToAbsolute(current).ToFloor(); - handler.PlaceBlock(block, Direction.Up, lookAtBlock: true); - handler.DoAnimation((int)Hand.MainHand); + handler.PlaceBlock(block, Direction.Up, hand, lookAtBlock: true); + handler.DoAnimation((int)hand); return r.SetAndReturn(Status.Done, Translations.cmd_useitem_use); } diff --git a/docs/guide/usage.md b/docs/guide/usage.md index b165ccd5..5d4d0768 100644 --- a/docs/guide/usage.md +++ b/docs/guide/usage.md @@ -1157,12 +1157,24 @@ In scripts and remote control, no slash is needed to perform the command, eg. `q /useitem ``` + Use the item from a specific hand: + + ``` + /useitem + ``` + Use the item on a specific block: ``` /useitem ``` + Use the item from a specific hand on a specific block: + + ``` + /useitem + ``` +