using System.Collections.Generic;
using System.Linq;
using MinecraftClient.Scripting;
namespace MinecraftClient.Inventory
{
///
/// Class that contains useful methods to move item around in a container
///
public class ItemMovingHelper
{
private readonly Container c;
private readonly McClient mc;
///
/// Create a helper that contains useful methods to move item around in container
///
/// Source container to use. All method will use this container for handling first slot parameter
/// McClient handler. Needed for sending WindowAction packet to the server
///
/// If you are using ChatBot API and cannot have direct access to McClient handler, use as second parameter
///
public ItemMovingHelper(Container c, McClient mc)
{
this.c = c;
this.mc = mc;
}
///
/// Move an item fron source to dest. Source should contain an item and dest slot should be empty
///
/// Source slot
/// Dest slot
/// Dest slot's container (only if dest slot is in other container)
/// True if success or false if Failed
public bool MoveTo(int source, int dest, Container? destContainer = null)
{
// Condition: source has item and dest has no item
if (ValidateSlots(source, dest, destContainer) &&
HasItem(source) &&
((destContainer != null && !HasItem(dest, destContainer)) || (destContainer == null && !HasItem(dest))))
return mc.DoWindowAction(c.ID, source, WindowActionType.LeftClick)
&& mc.DoWindowAction(destContainer == null ? c.ID : destContainer.ID, dest, WindowActionType.LeftClick);
else return false;
}
///
/// Swap two item. Both slots should contain item
///
/// Slot 1
/// Slot 2
/// Slot2 container (only if slot2 is in other container)
/// True if success or False if Failed
public bool Swap(int slot1, int slot2, Container? destContainer = null)
{
// Condition: Both slot1 and slot2 has item
if (ValidateSlots(slot1, slot2, destContainer) &&
HasItem(slot1) &&
(destContainer != null && HasItem(slot2, destContainer) || (destContainer == null && HasItem(slot2))))
return mc.DoWindowAction(c.ID, slot1, WindowActionType.LeftClick)
&& mc.DoWindowAction(destContainer == null ? c.ID : destContainer.ID, slot2, WindowActionType.LeftClick)
&& mc.DoWindowAction(c.ID, slot1, WindowActionType.LeftClick);
else return false;
}
///
/// Drag a stack of item over a set of slots. Those slots should be empty or have the same item as source item
///
/// Source item
/// Slots to be drag over
/// Which mouse key to use: StartDragLeft, StartDragRight or StartDragMiddle
/// True if success or false if Failed
///
/// After calling this method, you will need to wait until the server have updated the player inventory before doing next inventory action
///
public bool DragOverSlots(int source, IEnumerable slots, WindowActionType mouseKey = WindowActionType.StartDragLeft)
{
if (!HasItem(source))
return false;
List availableSlots = new(slots.Count());
// filter out different item type or non-empty slots (they will be ignored silently)
foreach (var slot in slots)
if (ItemTypeEqual(source, slot) || !HasItem(slot))
availableSlots.Add(slot);
if (availableSlots.Count > 0)
{
WindowActionType startDragging = WindowActionType.StartDragLeft;
WindowActionType addDragging = WindowActionType.AddDragLeft;
WindowActionType endDragging = WindowActionType.EndDragLeft;
switch (mouseKey)
{
case WindowActionType.StartDragRight:
{
startDragging = WindowActionType.StartDragRight;
addDragging = WindowActionType.AddDragRight;
endDragging = WindowActionType.EndDragRight;
break;
}
case WindowActionType.StartDragMiddle:
{
startDragging = WindowActionType.StartDragMiddle;
addDragging = WindowActionType.AddDragMiddle;
endDragging = WindowActionType.EndDragMiddle;
break;
}
}
mc.DoWindowAction(c.ID, source, WindowActionType.LeftClick); // grab item
mc.DoWindowAction(c.ID, -999, startDragging);
foreach (var slot in availableSlots)
{
mc.DoWindowAction(c.ID, slot, addDragging);
}
mc.DoWindowAction(c.ID, -999, endDragging);
mc.DoWindowAction(c.ID, source, WindowActionType.LeftClick); // put down item left (if any)
return true;
}
else return false;
}
///
/// Validate two slot by comparing they are different and within the maximum slot count of the container
///
/// Slot 1
/// Slot 2
/// Second container (only if slot2 is in other container)
/// The compare result
private bool ValidateSlots(int s1, int s2, Container? s2Container = null)
{
if (s2Container == null)
return (s1 != s2 && s1 < c.Type.SlotCount() && s2 < c.Type.SlotCount());
else
return (s1 < c.Type.SlotCount() && s2 < s2Container.Type.SlotCount());
}
///
/// Check if the slot has an item inside
///
/// Slot ID
/// Specify another contianer (only if the slot is in other container)
/// True if has item
private bool HasItem(int slot, Container? c = null)
{
c ??= this.c;
return c.Items.ContainsKey(slot);
}
///
/// Check both slots item type are the same
///
///
///
/// Second container (only if slot2 is in other container)
/// True if they are equal
private bool ItemTypeEqual(int slot1, int slot2, Container? s2Container = null)
{
if (s2Container == null)
{
if (HasItem(slot1) && HasItem(slot2))
return c.Items[slot1].Type == c.Items[slot2].Type;
else return false;
}
else
{
if (HasItem(slot1) && HasItem(slot2, s2Container))
return c.Items[slot1].Type == s2Container.Items[slot2].Type;
else return false;
}
}
}
}