装配矩阵上传优化
This commit is contained in:
parent
48e8b01384
commit
77edd13054
|
|
@ -2,6 +2,7 @@ package com.extendedae_plus.util;
|
|||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
public class GlobalSendMessage {
|
||||
/**
|
||||
|
|
@ -13,4 +14,10 @@ public class GlobalSendMessage {
|
|||
player.sendSystemMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendPlayerMessage(Player player, Component msg) {
|
||||
if (player != null) {
|
||||
player.sendSystemMessage(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,267 +13,180 @@ import appeng.menu.me.items.PatternEncodingTermMenu;
|
|||
import appeng.menu.slot.RestrictedInputSlot;
|
||||
import com.extendedae_plus.content.matrix.UploadCoreBlockEntity;
|
||||
import com.extendedae_plus.mixin.ae2.accessor.PatternEncodingTermMenuAccessor;
|
||||
import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixBase;
|
||||
import com.glodblock.github.extendedae.common.me.matrix.ClusterAssemblerMatrix;
|
||||
import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixPattern;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.common.capabilities.ForgeCapabilities;
|
||||
import net.minecraftforge.items.IItemHandler;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static com.extendedae_plus.util.GlobalSendMessage.sendPlayerMessage;
|
||||
|
||||
/**
|
||||
* 与装配矩阵 (assembler matrix) 上传 / 检查 相关的工具方法。
|
||||
* 保留原有逻辑与容错行为。
|
||||
* ExtendedAE 装配矩阵样板上传
|
||||
* 用于从 AE2 的样板编码终端上传至装配矩阵(仅合成样板)。
|
||||
*/
|
||||
public final class MatrixUploadUtil {
|
||||
private MatrixUploadUtil() {}
|
||||
/**
|
||||
* 发送消息给玩家
|
||||
*
|
||||
* @param player 玩家
|
||||
* @param message 消息内容
|
||||
*/
|
||||
private static void sendMessage(ServerPlayer player, String message) {
|
||||
// 静默:不再向玩家左下角发送任何提示信息
|
||||
// 如需恢复,取消下面注释即可:
|
||||
// if (player != null) {
|
||||
// player.sendSystemMessage(Component.literal(message));
|
||||
// }
|
||||
// 如果玩家为null,静默忽略(用于测试环境)
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 AE2 的图样编码终端菜单上传当前“已编码图样”至 ExtendedAE 装配矩阵(仅合成图样)。
|
||||
* 不会处理“处理图样”。
|
||||
* 从 AE2 的样板编码终端菜单上传当前“已编码合成样板”至 ExtendedAE 装配矩阵(仅合成样板)
|
||||
*
|
||||
* @param player 服务器玩家
|
||||
* @param menu PatternEncodingTermMenu
|
||||
* @return 是否成功插入矩阵
|
||||
*/
|
||||
public static boolean uploadFromEncodingMenuToMatrix(ServerPlayer player, PatternEncodingTermMenu menu) {
|
||||
if (player == null || menu == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void uploadFromEncodingMenuToMatrix(ServerPlayer player, PatternEncodingTermMenu menu) {
|
||||
if (player == null || menu == null) return;
|
||||
// 读取已编码槽位的物品
|
||||
RestrictedInputSlot encodedSlot = ((PatternEncodingTermMenuAccessor)menu).eap$getEncodedPatternSlot();
|
||||
RestrictedInputSlot encodedSlot = ((PatternEncodingTermMenuAccessor) menu).eap$getEncodedPatternSlot();
|
||||
ItemStack stack = encodedSlot.getItem();
|
||||
if (stack.isEmpty() || !PatternDetailsHelper.isEncodedPattern(stack)) {
|
||||
return false;
|
||||
}
|
||||
if (stack.isEmpty() || !PatternDetailsHelper.isEncodedPattern(stack)) return;
|
||||
|
||||
// 仅允许“合成/锻造台/切石机图样”
|
||||
// 仅允许“合成/锻造台/切石机样板”
|
||||
IPatternDetails details = PatternDetailsHelper.decodePattern(stack, player.level());
|
||||
if (!(details instanceof AECraftingPattern
|
||||
|| details instanceof AESmithingTablePattern
|
||||
|| details instanceof AEStonecuttingPattern)) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取 AE 网络
|
||||
IGridNode node = menu.getNetworkNode();
|
||||
if (node == null) {
|
||||
return false;
|
||||
}
|
||||
IGrid grid = node.getGrid();
|
||||
if (grid == null) {
|
||||
return false;
|
||||
}
|
||||
if (node == null) return;
|
||||
|
||||
// 在尝试上传之前,检查装配矩阵是否已经存在相同样板(物品与NBT完全一致)
|
||||
if (matrixContainsPattern(grid, stack)) {
|
||||
// 直接提醒并跳过上传,并将同等数量的空白样板放回空白样板槽,否则退回玩家背包
|
||||
if (player != null) {
|
||||
player.sendSystemMessage(Component.literal("ExtendedAE Plus: 装配矩阵已存在相同样板,已跳过上传并返还空白样板"));
|
||||
}
|
||||
try {
|
||||
var accessor = (PatternEncodingTermMenuAccessor) (Object) menu;
|
||||
var blankSlot = accessor.eap$getBlankPatternSlot();
|
||||
ItemStack blanks = AEItems.BLANK_PATTERN.stack(stack.getCount());
|
||||
if (blankSlot != null && blankSlot.mayPlace(blanks)) {
|
||||
ItemStack remain = blankSlot.safeInsert(blanks);
|
||||
if (!remain.isEmpty() && player != null) {
|
||||
player.getInventory().placeItemBackInInventory(remain, false);
|
||||
}
|
||||
} else if (player != null) {
|
||||
player.getInventory().placeItemBackInInventory(blanks, false);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (player != null) {
|
||||
// 兜底:直接还给玩家背包
|
||||
player.getInventory().placeItemBackInInventory(AEItems.BLANK_PATTERN.stack(stack.getCount()), false);
|
||||
}
|
||||
}
|
||||
// 清空编码样板槽,防止再次输出
|
||||
encodedSlot.set(ItemStack.EMPTY);
|
||||
return false;
|
||||
}
|
||||
IGrid grid = node.getGrid();
|
||||
if (grid == null) return;
|
||||
|
||||
int stackCount = stack.getCount();
|
||||
ItemStack toInsert = stack.copy();
|
||||
|
||||
// 收集所有可用的装配矩阵(图样模块)内部库存并逐一尝试(遵循其过滤规则)
|
||||
List<InternalInventory> inventories = findAllMatrixPatternInventories(grid);
|
||||
if (!inventories.isEmpty()) {
|
||||
for (int i = 0; i < inventories.size(); i++) {
|
||||
var inv = inventories.get(i);
|
||||
ItemStack toInsert = stack.copy();
|
||||
ItemStack remain = inv.addItems(toInsert);
|
||||
if (remain.getCount() < stack.getCount()) {
|
||||
int inserted = stack.getCount() - remain.getCount();
|
||||
stack.shrink(inserted);
|
||||
if (stack.isEmpty()) {
|
||||
encodedSlot.set(ItemStack.EMPTY);
|
||||
}
|
||||
sendMessage(player, "extendedae_plus.upload_to_matrix.success");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// 所有内部库存都无法接收 -> 尝试 capability 回退
|
||||
}
|
||||
|
||||
// 回退:尝试 Forge 能力(可能为聚合图样仓),同样遍历所有矩阵
|
||||
List<IItemHandler> handlers = findAllMatrixPatternHandlers(grid);
|
||||
if (!handlers.isEmpty()) {
|
||||
for (int i = 0; i < handlers.size(); i++) {
|
||||
var cap = handlers.get(i);
|
||||
ItemStack toInsert = stack.copy();
|
||||
ItemStack remain = insertIntoAnySlot(cap, toInsert);
|
||||
if (remain.getCount() < stack.getCount()) {
|
||||
int inserted = stack.getCount() - remain.getCount();
|
||||
stack.shrink(inserted);
|
||||
if (stack.isEmpty()) {
|
||||
encodedSlot.set(ItemStack.EMPTY);
|
||||
}
|
||||
sendMessage(player, "extendedae_plus.upload_to_matrix.success");
|
||||
return true;
|
||||
}
|
||||
// 在尝试上传之前,检查装配矩阵是否已经存在相同样板(物品与NBT完全一致)
|
||||
if (matrixContainsPattern(inventories, stack)) {
|
||||
// 直接提醒并跳过上传,并将同等数量的空白样板放回空白样板槽,否则退回玩家背包
|
||||
sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_matrix.repetition"));
|
||||
refundBlankPattern(player, menu, stackCount);
|
||||
encodedSlot.set(ItemStack.EMPTY);
|
||||
return;
|
||||
}
|
||||
// 尝试插入
|
||||
for (InternalInventory inv : inventories) {
|
||||
if (inv == null) continue;
|
||||
ItemStack remain = inv.addItems(toInsert);
|
||||
if (remain.getCount() < stackCount) {
|
||||
completeUploadSuccess(player, encodedSlot, stack, remain);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 未找到可用矩阵或全部拒收
|
||||
if (inventories.isEmpty() && handlers.isEmpty()) {
|
||||
sendMessage(player, "extendedae_plus.upload_to_matrix.fail_no_matrix");
|
||||
} else {
|
||||
sendMessage(player, "extendedae_plus.upload_to_matrix.fail_full");
|
||||
}
|
||||
return false;
|
||||
sendPlayerMessage(player,
|
||||
inventories.isEmpty()
|
||||
? Component.translatable("extendedae_plus.upload_to_matrix.fail_no_matrix")
|
||||
: Component.translatable("extendedae_plus.upload_to_matrix.fail_full"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 在给定 AE Grid 中收集所有已成型且在线的装配矩阵“图样模块”的用于外部插入的内部库存。
|
||||
* 优先使用 TileAssemblerMatrixPattern#getExposedInventory(仅允许插入,且已带AE过滤规则)。
|
||||
* 在给定 AE Grid 中收集所有已成型且在线的装配矩阵“样板核心”的用于外部插入的内部库存
|
||||
*/
|
||||
private static List<InternalInventory> findAllMatrixPatternInventories(IGrid grid) {
|
||||
List<InternalInventory> result = new ArrayList<>();
|
||||
if (grid == null) return result;
|
||||
|
||||
try {
|
||||
var tiles = grid.getMachines(TileAssemblerMatrixPattern.class);
|
||||
for (TileAssemblerMatrixPattern tile : tiles) {
|
||||
if (tile != null && tile.isFormed() && tile.getMainNode().isActive() && clusterHasSingleUploadCore(tile)) {
|
||||
var inv = tile.getExposedInventory();
|
||||
// 获取网络中所有 Pattern Tile
|
||||
Set<TileAssemblerMatrixPattern> allTiles = grid.getMachines(TileAssemblerMatrixPattern.class);
|
||||
// 用 Set 记录已经扫描过的集群,避免重复调用 clusterHasSingleUploadCore
|
||||
Set<ClusterAssemblerMatrix> scannedClusters = new HashSet<>();
|
||||
|
||||
for (TileAssemblerMatrixPattern tile : allTiles) {
|
||||
if (tile == null || !tile.isFormed() || !tile.getMainNode().isActive()) continue;
|
||||
|
||||
ClusterAssemblerMatrix cluster = tile.getCluster();
|
||||
if (cluster == null) continue;
|
||||
|
||||
// 如果该集群已经扫描过,或者该集群含 UploadCore,则处理 tile
|
||||
if (scannedClusters.contains(cluster) || clusterHasSingleUploadCore(cluster)) {
|
||||
scannedClusters.add(cluster); // 标记为已扫描
|
||||
|
||||
InternalInventory inv = tile.getExposedInventory();
|
||||
if (inv != null) {
|
||||
result.add(inv);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
} catch (Throwable ignored) {}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在给定 AE Grid 中收集所有已成型的装配矩阵的聚合图样仓 IItemHandler(若可用)。
|
||||
* 检查装配矩阵(所有已成型矩阵的样板核心)中是否已存在与给定样板完全相同的物品(含NBT)
|
||||
*/
|
||||
private static List<IItemHandler> findAllMatrixPatternHandlers(IGrid grid) {
|
||||
List<IItemHandler> result = new ArrayList<>();
|
||||
try {
|
||||
Set<TileAssemblerMatrixBase> matrices = grid.getMachines(TileAssemblerMatrixBase.class);
|
||||
for (TileAssemblerMatrixBase tile : matrices) {
|
||||
if (tile != null && tile.isFormed() && clusterHasSingleUploadCore(tile)) {
|
||||
var capOpt = tile.getCapability(ForgeCapabilities.ITEM_HANDLER, null);
|
||||
if (capOpt != null) {
|
||||
var handler = capOpt.orElse(null);
|
||||
if (handler != null) {
|
||||
result.add(handler);
|
||||
}
|
||||
}
|
||||
private static boolean matrixContainsPattern(@NotNull List<InternalInventory> inventories, @NotNull ItemStack pattern) {
|
||||
for (InternalInventory inv : inventories) {
|
||||
if (inv == null) continue;
|
||||
for (int i = 0; i < inv.size(); i++) {
|
||||
ItemStack s = inv.getStackInSlot(i);
|
||||
if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查装配矩阵(所有已成型矩阵的图样仓)中是否已存在与给定样板完全相同的物品(含NBT)。
|
||||
*/
|
||||
private static boolean matrixContainsPattern(IGrid grid, ItemStack pattern) {
|
||||
if (grid == null || pattern == null || pattern.isEmpty()) return false;
|
||||
try {
|
||||
// 先检查提供外部插入视图的内部库存
|
||||
List<InternalInventory> inventories = findAllMatrixPatternInventories(grid);
|
||||
for (InternalInventory inv : inventories) {
|
||||
if (inv == null) continue;
|
||||
for (int i = 0; i < inv.size(); i++) {
|
||||
ItemStack s = inv.getStackInSlot(i);
|
||||
if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
try {
|
||||
// 再检查聚合能力视图
|
||||
List<IItemHandler> handlers = findAllMatrixPatternHandlers(grid);
|
||||
for (IItemHandler h : handlers) {
|
||||
if (h == null) continue;
|
||||
int slots = h.getSlots();
|
||||
for (int i = 0; i < slots; i++) {
|
||||
ItemStack s = h.getStackInSlot(i);
|
||||
if (!s.isEmpty() && ItemStack.isSameItemSameTags(s, pattern)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定矩阵集群中是否存在“装配矩阵上传核心”。
|
||||
* 要求:至少存在 1 个即可,不限制数量。
|
||||
* 传入任意属于该集群的 Tile(如 Pattern/Crafter/Frame 等)。
|
||||
*/
|
||||
private static boolean clusterHasSingleUploadCore(TileAssemblerMatrixBase any) {
|
||||
private static boolean clusterHasSingleUploadCore(@NotNull ClusterAssemblerMatrix cluster) {
|
||||
try {
|
||||
if (any == null || any.getCluster() == null) return false;
|
||||
int cores = 0;
|
||||
var it = any.getCluster().getBlockEntities();
|
||||
var it = cluster.getBlockEntities();
|
||||
while (it.hasNext()) {
|
||||
var te = it.next();
|
||||
if (te instanceof UploadCoreBlockEntity) {
|
||||
cores++;
|
||||
}
|
||||
if (it.next() instanceof UploadCoreBlockEntity) return true;
|
||||
}
|
||||
return cores >= 1; // 至少一个即可
|
||||
} catch (Throwable t) {
|
||||
return false;
|
||||
} catch (Throwable ignored) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传成功后处理:清空编码槽,发送提示。
|
||||
*/
|
||||
private static void completeUploadSuccess(ServerPlayer player, RestrictedInputSlot encodedSlot, ItemStack stack, ItemStack remain) {
|
||||
int inserted = stack.getCount() - remain.getCount();
|
||||
if (inserted > 0) {
|
||||
stack.shrink(inserted);
|
||||
if (stack.isEmpty()) encodedSlot.set(ItemStack.EMPTY);
|
||||
sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_matrix.success"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 尝试将整个物品栈插入到 IItemHandler 的任意槽位,返回剩余物品。
|
||||
* 当发现重复样板时返还空白样板。
|
||||
*/
|
||||
private static ItemStack insertIntoAnySlot(IItemHandler handler, ItemStack stack) {
|
||||
ItemStack remaining = stack.copy();
|
||||
if (handler == null || remaining.isEmpty()) return remaining;
|
||||
for (int i = 0; i < handler.getSlots(); i++) {
|
||||
remaining = handler.insertItem(i, remaining, false);
|
||||
if (remaining.isEmpty()) break;
|
||||
private static void refundBlankPattern(ServerPlayer player, PatternEncodingTermMenu menu, int count) {
|
||||
try {
|
||||
var accessor = (PatternEncodingTermMenuAccessor) menu;
|
||||
var blankSlot = accessor.eap$getBlankPatternSlot();
|
||||
ItemStack blanks = AEItems.BLANK_PATTERN.stack(count);
|
||||
if (blankSlot != null && blankSlot.mayPlace(blanks)) {
|
||||
ItemStack remain = blankSlot.safeInsert(blanks);
|
||||
if (!remain.isEmpty() && player != null) {
|
||||
player.getInventory().placeItemBackInInventory(remain, false);
|
||||
}
|
||||
} else if (player != null) {
|
||||
player.getInventory().placeItemBackInInventory(blanks, false);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
if (player != null) {
|
||||
player.getInventory().placeItemBackInInventory(AEItems.BLANK_PATTERN.stack(count), false);
|
||||
}
|
||||
}
|
||||
return remaining;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,6 +49,9 @@
|
|||
"extendedae_plus.upload_to_matrix.fail_not_crafting": "仅支持上传合成样板,处理样板将被忽略",
|
||||
"extendedae_plus.upload_to_matrix.fail_no_matrix": "未在当前网络中找到已成型的装配矩阵",
|
||||
"extendedae_plus.upload_to_matrix.fail_full": "装配矩阵的样板仓已满或无法插入",
|
||||
"extendedae_plus.upload_to_matrix.repetition": "装配矩阵已存在相同样板,已跳过上传并返还空白样板",
|
||||
|
||||
|
||||
"extendedae_plus.screen.reload_mapping": "重载映射",
|
||||
"extendedae_plus.screen.reload_mapping_success": "重载映射成功",
|
||||
"extendedae_plus.screen.reload_mapping_fail": "重载映射失败: %s",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user