核心改进: - 实时状态 HUD(左上角面板:任务/状态/时长/血量/饥饿/背包/进度) - 自动插火把(黑暗隧道自动防灾,可开关) - 自动进食跳过金苹果/附魔金苹果/紫颂果等特殊食物 - 背包接近满(≥30格)即提前丢垃圾,防误判满包返回 - 杀戮光环排除 Angerable 中立生物(僵尸猪灵/末影人/狼等) - 新增 /autodig status 命令 - GUI 补全设置:自动插火把、进食阈值、保命血量、攻击范围 - 会话统计(时长/死亡次数)联动 HUD 与命令 - 补全 README.md 文档 - 版本升至 2.2.0
145 行
5.3 KiB
Java
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();
|
|
}
|
|
} |