文件
AutoDig/src/main/java/autodig/client/service/AutoTrash.java
T
lyizai 4135cdd117 feat: 智能升级 v2.2.0 - HUD/AutoTorch/AutoEat 智能食物/提前丢垃圾/剔除中立生物
核心改进:
- 实时状态 HUD(左上角面板:任务/状态/时长/血量/饥饿/背包/进度)
- 自动插火把(黑暗隧道自动防灾,可开关)
- 自动进食跳过金苹果/附魔金苹果/紫颂果等特殊食物
- 背包接近满(≥30格)即提前丢垃圾,防误判满包返回
- 杀戮光环排除 Angerable 中立生物(僵尸猪灵/末影人/狼等)
- 新增 /autodig status 命令
- GUI 补全设置:自动插火把、进食阈值、保命血量、攻击范围
- 会话统计(时长/死亡次数)联动 HUD 与命令
- 补全 README.md 文档
- 版本升至 2.2.0
2026-08-30 22:36:35 +08:00

145 行
5.3 KiB
Java

package autodig.client.service;
import autodig.client.config.DigConfig;
import autodig.client.config.MineTask;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.minecraft.client.MinecraftClient;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.item.ItemStack;
import net.minecraft.registry.Registries;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.SlotActionType;
/**
* 背包垃圾自动清理服务。
*
* <p>背包接近满(已用格数达到阈值)时就主动把 {@code trashItems} 清单里的
* 垃圾物品丢出背包(圆石、凝灰岩、深板岩等挖掘副产物),为挖到的矿物提前
* 腾出空间,避免背包彻底满后触发"背包已满需返回"而中断挖矿。方块类垃圾
* 保留 {@code trashReserve} 个供 Baritone 搭路/垫脚使用。丢弃通过
* {@code clickSlot(THROW)} 走正规网络包,单人/多人均可用。</p>
*/
public final class AutoTrash {
/** 每 tick 最多丢弃的物品组数,避免一次产生过多数据包 */
private static final int MAX_DROPS_PER_TICK = 4;
/** 背包已用格数达到该值(共 36 格)即开始丢垃圾,留出余量防误判满包 */
private static final int NEARLY_FULL_SLOTS = 30;
/** 每帧调用:背包接近满时提前丢弃垃圾物品。 */
public void tick(DigConfig config) {
MinecraftClient client = MinecraftClient.getInstance();
if (client.player == null || client.world == null || client.interactionManager == null) {
return;
}
if (!config.autoTrash || config.task == MineTask.NONE) {
return;
}
if (client.currentScreen != null) {
return; // 有界面(箱子/死亡界面等)打开时不操作背包
}
PlayerEntity player = client.player;
ScreenHandler handler = player.currentScreenHandler;
if (handler != player.playerScreenHandler) {
return;
}
if (!handler.getCursorStack().isEmpty()) {
return;
}
// 背包接近满才开始丢,避免背包还没满就误丢
if (this.usedSlots(player) < NEARLY_FULL_SLOTS) {
return;
}
Set<String> trash = new HashSet<>(config.getTrashItemList());
if (trash.isEmpty()) {
return;
}
// 收集背包里的垃圾,按物品 id 分组(并记录是否为可放置的方块)
Map<String, List<ItemStack>> groups = new HashMap<>();
Map<String, Boolean> blockLike = new HashMap<>();
for (int i = 0; i < 36; i++) {
ItemStack s = player.getInventory().main.get(i);
if (s.isEmpty()) {
continue;
}
String id = this.itemId(s);
if (!trash.contains(id)) {
continue;
}
groups.computeIfAbsent(id, k -> new ArrayList<>()).add(s);
blockLike.putIfAbsent(id, s.getItem() instanceof BlockItem);
}
if (groups.isEmpty()) {
return;
}
// 决定丢弃哪些:方块类垃圾保留 trashReserve 个(搭路用),非方块全丢
List<ItemStack> drops = new ArrayList<>();
for (Map.Entry<String, List<ItemStack>> e : groups.entrySet()) {
int keep = Boolean.TRUE.equals(blockLike.get(e.getKey())) ? config.trashReserve : 0;
for (ItemStack s : e.getValue()) {
if (keep > 0) {
keep -= s.getCount();
continue; // 还在保留额度内
}
drops.add(s);
}
}
if (drops.isEmpty()) {
// 满背但垃圾全在保留额度内:只丢一组腾出空间,尽量保住搭路方块
for (List<ItemStack> list : groups.values()) {
if (!list.isEmpty()) {
drops.add(list.get(0));
break;
}
}
}
// 执行丢弃(每 tick 限量,剩余下 tick 继续)
int dropped = 0;
for (ItemStack s : drops) {
if (dropped >= MAX_DROPS_PER_TICK) {
break;
}
int slot = this.screenSlotOf(handler, s);
if (slot < 0) {
continue;
}
// THROW + 按钮 1 = 丢出整组
client.interactionManager.clickSlot(handler.syncId, slot, 1, SlotActionType.THROW, player);
dropped++;
}
}
/** 统计背包已用格数(快捷栏 + 主背包 0-35,共 36 格)。 */
private int usedSlots(PlayerEntity player) {
int used = 0;
for (int i = 0; i < 36; i++) {
if (!player.getInventory().main.get(i).isEmpty()) {
used++;
}
}
return used;
}
/** 按对象引用在 ScreenHandler 里找槽位下标。 */
private int screenSlotOf(ScreenHandler handler, ItemStack stack) {
for (int i = 0; i < handler.slots.size(); i++) {
if (handler.getSlot(i).getStack() == stack) {
return i;
}
}
return -1;
}
private String itemId(ItemStack stack) {
return Registries.ITEM.getId(stack.getItem()).toString();
}
}