修复使用内存卡刷取实体加速卡的bug

This commit is contained in:
GaLi 2026-04-16 18:31:31 +08:00
parent 56a64b921c
commit c8ae498808

View File

@ -14,6 +14,7 @@ import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
@ -23,6 +24,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
@Mixin(value = MemoryCardItem.class, remap = false) @Mixin(value = MemoryCardItem.class, remap = false)
public class MemoryCardItemMixin { public class MemoryCardItemMixin {
@ -46,7 +49,6 @@ public class MemoryCardItemMixin {
if (upgradeStack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) { if (upgradeStack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) {
CompoundTag stackTag = new CompoundTag(); CompoundTag stackTag = new CompoundTag();
stackTag.putInt("Slot", i);
upgradeStack.save(stackTag); upgradeStack.save(stackTag);
entitySpeedCards.add(stackTag); entitySpeedCards.add(stackTag);
} else { } else {
@ -78,6 +80,8 @@ public class MemoryCardItemMixin {
CompoundTag desiredUpgradesTag = input.getCompound("upgrades"); CompoundTag desiredUpgradesTag = input.getCompound("upgrades");
InternalInventory upgrades = upgradeableObject.getUpgrades(); InternalInventory upgrades = upgradeableObject.getUpgrades();
var desiredUpgrades = new IdentityHashMap<Item, Integer>();
var desiredEntitySpeedCards = new ArrayList<ItemStack>();
// 收集背包和网络工具作为升级卡来源 // 收集背包和网络工具作为升级卡来源
var upgradeSources = new ArrayList<InternalInventory>(); var upgradeSources = new ArrayList<InternalInventory>();
@ -87,11 +91,83 @@ public class MemoryCardItemMixin {
upgradeSources.add(networkTool.getInventory()); upgradeSources.add(networkTool.getInventory());
} }
// 清空所有槽位中的 EntitySpeedCardItem if (desiredUpgradesTag.contains("entity_speed_cards", Tag.TAG_LIST)) {
ListTag entitySpeedCards = desiredUpgradesTag.getList("entity_speed_cards", Tag.TAG_COMPOUND);
for (int i = 0; i < entitySpeedCards.size(); i++) {
ItemStack desiredStack = ItemStack.of(entitySpeedCards.getCompound(i));
if (!desiredStack.isEmpty()) {
desiredEntitySpeedCards.add(desiredStack);
}
}
}
for (String key : desiredUpgradesTag.getAllKeys()) {
if ("entity_speed_cards".equals(key)) {
continue;
}
ResourceLocation id;
try {
id = new ResourceLocation(key);
} catch (Exception ex) {
continue;
}
var item = BuiltInRegistries.ITEM.getOptional(id).orElse(null);
if (item == null || item.equals(ModItems.ENTITY_SPEED_CARD.get())) {
continue;
}
int desiredCount = desiredUpgradesTag.getInt(key);
if (desiredCount > 0) {
desiredUpgrades.put(item, desiredCount);
}
}
if (player.getAbilities().instabuild) {
for (int i = 0; i < upgrades.size(); i++) {
upgrades.setItemDirect(i, ItemStack.EMPTY);
}
for (var desiredStack : desiredEntitySpeedCards) {
upgrades.addItems(desiredStack.copy());
}
for (var entry : desiredUpgrades.entrySet()) {
upgrades.addItems(new ItemStack(entry.getKey(), entry.getValue()));
}
markUpgradesChanged(upgradeableObject);
cir.setReturnValue(true);
return;
}
// 先精确移除多余的实体加速卡按完整 NBT 匹配
var desiredEntityStacks = new ArrayList<ItemStack>();
var desiredEntityCounts = new ArrayList<Integer>();
for (var desiredStack : desiredEntitySpeedCards) {
mergeExactCount(desiredEntityStacks, desiredEntityCounts, desiredStack, desiredStack.getCount());
}
var currentEntityStacks = new ArrayList<ItemStack>();
var currentEntityCounts = new ArrayList<Integer>();
collectInstalledEntitySpeedCards(upgrades, currentEntityStacks, currentEntityCounts);
for (int i = 0; i < upgrades.size(); i++) { for (int i = 0; i < upgrades.size(); i++) {
ItemStack stack = upgrades.getStackInSlot(i); ItemStack stack = upgrades.getStackInSlot(i);
if (!stack.isEmpty() && stack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) { if (stack.isEmpty() || !stack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) {
ItemStack removed = upgrades.extractItem(i, stack.getCount(), false); continue;
}
int installed = getExactCount(currentEntityStacks, currentEntityCounts, stack);
int desired = getExactCount(desiredEntityStacks, desiredEntityCounts, stack);
int excess = installed - desired;
if (excess <= 0) {
continue;
}
ItemStack removed = upgrades.extractItem(i, Math.min(excess, stack.getCount()), false);
if (removed.isEmpty()) {
continue;
}
decrementExactCount(currentEntityStacks, currentEntityCounts, stack, removed.getCount());
for (var source : upgradeSources) { for (var source : upgradeSources) {
if (!removed.isEmpty()) { if (!removed.isEmpty()) {
removed = source.addItems(removed); removed = source.addItems(removed);
@ -101,83 +177,82 @@ public class MemoryCardItemMixin {
player.drop(removed, false); player.drop(removed, false);
} }
} }
// AE2 原逻辑移除多余的其他升级卡
for (int i = 0; i < upgrades.size(); i++) {
var current = upgrades.getStackInSlot(i);
if (current.isEmpty() || current.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) {
continue;
} }
// 恢复 EntitySpeedCardItem var desiredCount = desiredUpgrades.getOrDefault(current.getItem(), 0);
if (desiredUpgradesTag.contains("entity_speed_cards", Tag.TAG_LIST)) { var totalInstalled = upgradeableObject.getInstalledUpgrades(current.getItem());
ListTag entitySpeedCards = desiredUpgradesTag.getList("entity_speed_cards", Tag.TAG_COMPOUND); var toRemove = totalInstalled - desiredCount;
for (int i = 0; i < entitySpeedCards.size(); i++) { if (toRemove > 0) {
CompoundTag stackTag = entitySpeedCards.getCompound(i); var removed = upgrades.extractItem(i, toRemove, false);
ItemStack desiredStack = ItemStack.of(stackTag);
int slot = stackTag.contains("Slot") ? stackTag.getInt("Slot") : i;
if (player.getAbilities().instabuild) { for (var upgradeSource : upgradeSources) {
// 创造模式直接生成 if (!removed.isEmpty()) {
if (slot >= 0 && slot < upgrades.size()) { removed = upgradeSource.addItems(removed);
upgrades.setItemDirect(slot, desiredStack); }
} else { }
upgrades.addItems(desiredStack); if (!removed.isEmpty()) {
player.drop(removed, false);
}
}
}
// 精确补回缺失的实体加速卡按完整 NBT 匹配
var afterRemovalEntityStacks = new ArrayList<ItemStack>();
var afterRemovalEntityCounts = new ArrayList<Integer>();
collectInstalledEntitySpeedCards(upgrades, afterRemovalEntityStacks, afterRemovalEntityCounts);
for (int i = 0; i < desiredEntityStacks.size(); i++) {
var desiredStack = desiredEntityStacks.get(i);
int desiredCount = desiredEntityCounts.get(i);
int missingAmount = desiredCount - getExactCount(afterRemovalEntityStacks, afterRemovalEntityCounts, desiredStack);
if (missingAmount <= 0) {
continue;
}
var potential = desiredStack.copy();
potential.setCount(missingAmount);
var overflow = upgrades.addItems(potential, true);
if (!overflow.isEmpty()) {
missingAmount -= overflow.getCount();
}
if (missingAmount <= 0) {
continue;
} }
} else {
// 非创造模式从背包或网络工具提取
int missingAmount = desiredStack.getCount();
ItemStack extracted = ItemStack.EMPTY;
for (var source : upgradeSources) { for (var source : upgradeSources) {
ItemStack potential = new ItemStack(desiredStack.getItem(), missingAmount); var preciseRequest = desiredStack.copy();
if (desiredStack.hasTag()) { preciseRequest.setCount(missingAmount);
potential.setTag(desiredStack.getTag().copy()); var cards = source.removeItems(missingAmount, preciseRequest, null);
}
ItemStack cards = source.removeItems(missingAmount, potential, null);
if (!cards.isEmpty()) { if (!cards.isEmpty()) {
ItemStack overflow = upgrades.addItems(cards); overflow = upgrades.addItems(cards);
if (!overflow.isEmpty()) { if (!overflow.isEmpty()) {
player.getInventory().placeItemBackInInventory(overflow); player.getInventory().placeItemBackInInventory(overflow);
} }
missingAmount -= cards.getCount(); missingAmount -= cards.getCount();
extracted = cards;
} }
if (missingAmount <= 0) break; if (missingAmount <= 0) {
break;
}
} }
if (missingAmount > 0 && !player.level().isClientSide()) { if (missingAmount > 0 && !player.level().isClientSide()) {
player.displayClientMessage( player.displayClientMessage(
PlayerMessages.MissingUpgrades.text(desiredStack.getItem().getDescription(), missingAmount), PlayerMessages.MissingUpgrades.text(desiredStack.getHoverName(), missingAmount),
true true
); );
} else if (!extracted.isEmpty()) {
if (slot >= 0 && slot < upgrades.size()) {
upgrades.setItemDirect(slot, extracted);
} else {
upgrades.addItems(extracted);
}
}
}
} }
} }
// 恢复其他升级卡 AE2 原逻辑 // 恢复其他升级卡 AE2 原逻辑
for (String key : desiredUpgradesTag.getAllKeys()) { for (var entry : desiredUpgrades.entrySet()) {
ResourceLocation id; int missingAmount = entry.getValue() - upgradeableObject.getInstalledUpgrades(entry.getKey());
try { if (missingAmount > 0) {
id = new ResourceLocation(key); ItemStack potential = new ItemStack(entry.getKey(), missingAmount);
} catch (Exception ex) {
continue;
}
var item = BuiltInRegistries.ITEM.getOptional(id).orElse(null);
if (item == null || item.equals(ModItems.ENTITY_SPEED_CARD.get())) continue;
int desiredCount = desiredUpgradesTag.getInt(key);
if (desiredCount > 0) {
if (player.getAbilities().instabuild) {
// 创造模式直接生成
ItemStack stack = new ItemStack(item, desiredCount);
upgrades.addItems(stack);
} else {
// 非创造模式从背包或网络工具提取
int missingAmount = desiredCount;
ItemStack potential = new ItemStack(item, missingAmount);
ItemStack overflow = upgrades.addItems(potential, true); ItemStack overflow = upgrades.addItems(potential, true);
if (!overflow.isEmpty()) { if (!overflow.isEmpty()) {
missingAmount -= overflow.getCount(); missingAmount -= overflow.getCount();
@ -197,15 +272,22 @@ public class MemoryCardItemMixin {
if (missingAmount > 0 && !player.level().isClientSide()) { if (missingAmount > 0 && !player.level().isClientSide()) {
player.displayClientMessage( player.displayClientMessage(
PlayerMessages.MissingUpgrades.text(item.getDescription(), missingAmount), PlayerMessages.MissingUpgrades.text(entry.getKey().getDescription(), missingAmount),
true true
); );
} }
} }
} }
markUpgradesChanged(upgradeableObject);
cir.setReturnValue(true);
} catch (Exception e) {
e.printStackTrace();
cir.setReturnValue(false);
}
} }
// 标记保存并通知升级变化 private static void markUpgradesChanged(IUpgradeableObject upgradeableObject) {
if (upgradeableObject instanceof EntitySpeedTickerPart speedTickerPart) { if (upgradeableObject instanceof EntitySpeedTickerPart speedTickerPart) {
BlockEntity be = speedTickerPart.getBlockEntity(); BlockEntity be = speedTickerPart.getBlockEntity();
if (be != null) { if (be != null) {
@ -213,11 +295,68 @@ public class MemoryCardItemMixin {
} }
speedTickerPart.upgradesChanged(); speedTickerPart.upgradesChanged();
} }
}
cir.setReturnValue(true); private static void collectInstalledEntitySpeedCards(InternalInventory upgrades, List<ItemStack> stacks,
} catch (Exception e) { List<Integer> counts) {
e.printStackTrace(); for (int i = 0; i < upgrades.size(); i++) {
cir.setReturnValue(false); var stack = upgrades.getStackInSlot(i);
if (!stack.isEmpty() && stack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) {
mergeExactCount(stacks, counts, stack, stack.getCount());
} }
} }
} }
private static void mergeExactCount(List<ItemStack> stacks, List<Integer> counts, ItemStack stack, int amount) {
if (stack.isEmpty() || amount <= 0) {
return;
}
for (int i = 0; i < stacks.size(); i++) {
if (sameExactStack(stacks.get(i), stack)) {
counts.set(i, counts.get(i) + amount);
return;
}
}
stacks.add(copySingle(stack));
counts.add(amount);
}
private static int getExactCount(List<ItemStack> stacks, List<Integer> counts, ItemStack stack) {
for (int i = 0; i < stacks.size(); i++) {
if (sameExactStack(stacks.get(i), stack)) {
return counts.get(i);
}
}
return 0;
}
private static void decrementExactCount(List<ItemStack> stacks, List<Integer> counts, ItemStack stack, int amount) {
if (amount <= 0) {
return;
}
for (int i = 0; i < stacks.size(); i++) {
if (sameExactStack(stacks.get(i), stack)) {
int remaining = counts.get(i) - amount;
if (remaining <= 0) {
stacks.remove(i);
counts.remove(i);
} else {
counts.set(i, remaining);
}
return;
}
}
}
private static boolean sameExactStack(ItemStack a, ItemStack b) {
return ItemStack.isSameItemSameTags(a, b);
}
private static ItemStack copySingle(ItemStack stack) {
var copy = stack.copy();
copy.setCount(1);
return copy;
}
}