This commit is contained in:
LangQi99 2026-05-25 19:32:33 +08:00 committed by GitHub
commit 87f6d643d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 205 additions and 5 deletions

View File

@ -202,6 +202,12 @@ public final class ModNetwork {
.decoder(CancelPendingPatternC2SPacket::decode)
.consumerNetworkThread(CancelPendingPatternC2SPacket::handle)
.add();
CHANNEL.messageBuilder(ReturnLastPatternC2SPacket.class,nextId(), NetworkDirection.PLAY_TO_SERVER)
.encoder(ReturnLastPatternC2SPacket::encode)
.decoder(ReturnLastPatternC2SPacket::decode)
.consumerNetworkThread(ReturnLastPatternC2SPacket::handle)
.add();
}
private static int nextId() { return id++; }

View File

@ -12,6 +12,7 @@ import com.extendedae_plus.mixin.ae2.accessor.AEBaseScreenAccessor;
import com.extendedae_plus.mixin.minecraft.accessor.AbstractContainerScreenAccessor;
import com.extendedae_plus.mixin.minecraft.accessor.ScreenAccessor;
import com.extendedae_plus.network.provider.RequestProvidersListC2SPacket;
import com.extendedae_plus.network.provider.ReturnLastPatternC2SPacket;
import com.extendedae_plus.network.upload.EncodeWithShiftFlagC2SPacket;
import com.mojang.blaze3d.systems.RenderSystem;
import net.minecraft.client.gui.GuiGraphics;
@ -66,9 +67,13 @@ public abstract class PatternEncodingTermScreenMixin {
@Unique
private IconButton createUploadButton() {
IconButton btn = new IconButton(button ->
ModNetwork.CHANNEL.sendToServer(new RequestProvidersListC2SPacket())
) {
IconButton btn = new IconButton(button -> {
if (Screen.hasShiftDown()) {
ModNetwork.CHANNEL.sendToServer(new ReturnLastPatternC2SPacket());
} else {
ModNetwork.CHANNEL.sendToServer(new RequestProvidersListC2SPacket());
}
}) {
private final float eap$scale = 0.75f;
@Override
@ -99,7 +104,19 @@ public abstract class PatternEncodingTermScreenMixin {
if (!this.isDisableBackground()) {
Icon.TOOLBAR_BUTTON_BACKGROUND.getBlitter().dest(0, 0).blit(guiGraphics);
}
blitter.dest(0, 0).blit(guiGraphics);
if (Screen.hasShiftDown()) {
pose.pushPose();
// Rotate around the center of the 16x16 icon
pose.translate(8.0f, 8.0f, 0.0f);
pose.mulPose(com.mojang.math.Axis.ZP.rotationDegrees(180.0f));
pose.translate(-8.0f, -8.0f, 0.0f);
blitter.dest(0, 0).blit(guiGraphics);
pose.popPose();
} else {
blitter.dest(0, 0).blit(guiGraphics);
}
pose.popPose();
RenderSystem.enableDepthTest();
@ -110,6 +127,16 @@ public abstract class PatternEncodingTermScreenMixin {
return new Rect2i(getX(), getY(), Math.round(16 * eap$scale), Math.round(16 * eap$scale));
}
@Override
public void render(GuiGraphics p_281670_, int p_282682_, int p_281714_, float p_282542_) {
if (Screen.hasShiftDown()) {
this.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.return_last_pattern")));
} else {
this.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.choose_provider")));
}
super.render(p_281670_, p_282682_, p_281714_, p_282542_);
}
@Override
protected Icon getIcon() {
return Icon.ARROW_UP;

View File

@ -0,0 +1,138 @@
package com.extendedae_plus.network.provider;
import appeng.api.crafting.PatternDetailsHelper;
import appeng.api.inventories.InternalInventory;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode;
import appeng.helpers.patternprovider.PatternContainer;
import appeng.menu.implementations.PatternAccessTermMenu;
import appeng.menu.me.items.PatternEncodingTermMenu;
import com.extendedae_plus.util.PatternTerminalUtil;
import com.extendedae_plus.util.uploadPattern.ProviderUploadUtil;
import com.glodblock.github.extendedae.common.tileentities.matrix.TileAssemblerMatrixPattern;
import com.extendedae_plus.content.matrix.PatternCorePlusBlockEntity;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraftforge.network.NetworkEvent;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;
/**
* C2S: Retrieved the last uploaded pattern from the recently used provider.
*/
public class ReturnLastPatternC2SPacket {
public ReturnLastPatternC2SPacket() {}
public static void encode(ReturnLastPatternC2SPacket msg, FriendlyByteBuf buf) {}
public static ReturnLastPatternC2SPacket decode(FriendlyByteBuf buf) {
return new ReturnLastPatternC2SPacket();
}
public static void handle(ReturnLastPatternC2SPacket msg, Supplier<NetworkEvent.Context> ctxSupplier) {
var ctx = ctxSupplier.get();
ctx.enqueueWork(() -> {
ServerPlayer player = ctx.getSender();
if (player == null) return;
long lastProviderId = ProviderUploadUtil.getLastUploadedProviderId(player);
if (lastProviderId == Long.MIN_VALUE) {
return; // Nothing to return
}
// Special ID for Assembly Matrix
if (lastProviderId == -999999L) {
if (player.containerMenu instanceof PatternEncodingTermMenu encMenu) {
IGridNode node = encMenu.getNetworkNode();
if (node != null && node.getGrid() != null) {
IGrid grid = node.getGrid();
// Get all matrix pattern inventories
try {
Set<TileAssemblerMatrixPattern> allTiles = grid.getMachines(TileAssemblerMatrixPattern.class);
for (TileAssemblerMatrixPattern tile : allTiles) {
if (tile != null && tile.isFormed() && tile.getMainNode().isActive()) {
InternalInventory inv = tile.getTerminalPatternInventory();
if (inv != null && returnPatternFromInventory(player, inv)) {
return;
}
}
}
Set<PatternCorePlusBlockEntity> myAllTiles = grid.getMachines(PatternCorePlusBlockEntity.class);
for (PatternCorePlusBlockEntity tile : myAllTiles) {
if (tile != null && tile.isFormed() && tile.getMainNode().isActive()) {
InternalInventory inv = tile.getTerminalPatternInventory();
if (inv != null && returnPatternFromInventory(player, inv)) {
return;
}
}
}
} catch (Exception ignored) {}
}
}
return;
}
PatternContainer targetContainer = null;
// Try to resolve the container using encoding menu
if (player.containerMenu instanceof PatternEncodingTermMenu encMenu) {
if (lastProviderId >= 0) {
PatternAccessTermMenu accessMenu = PatternTerminalUtil.getPatternAccessMenu(player);
if (accessMenu != null) {
targetContainer = PatternTerminalUtil.getPatternContainerById(accessMenu, lastProviderId);
}
} else {
int index = (int) (-1L - lastProviderId);
List<PatternContainer> list = PatternTerminalUtil.listAvailableProvidersFromGrid(encMenu);
if (index >= 0 && index < list.size()) {
targetContainer = list.get(index);
}
}
} else {
// Try to resolve from player network if not in encoding menu (e.g. pending ctrl+q state)
if (lastProviderId >= 0) {
// It's harder without access terminal menu, but technically we could search the grid
return;
} else {
int index = (int) (-1L - lastProviderId);
List<PatternContainer> list = ProviderUploadUtil.listAvailableProvidersFromPlayerNetwork(player);
if (index >= 0 && index < list.size()) {
targetContainer = list.get(index);
}
}
}
if (targetContainer == null || !targetContainer.isVisibleInTerminal()) {
return;
}
InternalInventory inv = targetContainer.getTerminalPatternInventory();
if (inv != null && inv.size() > 0) {
returnPatternFromInventory(player, inv);
}
});
ctx.setPacketHandled(true);
}
private static boolean returnPatternFromInventory(ServerPlayer player, InternalInventory inv) {
// Find the highest slot with an encoded pattern
for (int slot = inv.size() - 1; slot >= 0; slot--) {
ItemStack stack = inv.getStackInSlot(slot);
if (!stack.isEmpty() && PatternDetailsHelper.isEncodedPattern(stack)) {
ItemStack extracted = inv.extractItem(slot, 1, false);
if (!extracted.isEmpty()) {
if (!player.getInventory().add(extracted)) {
player.drop(extracted, false);
}
return true; // Found and returned
}
}
}
return false;
}
}

View File

@ -132,6 +132,7 @@ public final class MatrixUploadUtil {
if (remain.getCount() < pattern.getCount()) {
// 上传成功
sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_matrix.success"));
player.getPersistentData().putLong("eap_last_uploaded_provider_id", -999999L);
return true;
}
}
@ -146,7 +147,7 @@ public final class MatrixUploadUtil {
/**
* 在给定 AE Grid 中收集所有已成型且在线的装配矩阵样板核心的用于外部插入的内部库存
*/
private static List<InternalInventory> findAllMatrixPatternInventories(IGrid grid) {
public static List<InternalInventory> findAllMatrixPatternInventories(IGrid grid) {
List<InternalInventory> result = new ArrayList<>();
if (grid == null) return result;
@ -242,6 +243,7 @@ public final class MatrixUploadUtil {
stack.shrink(inserted);
if (stack.isEmpty()) encodedSlot.set(ItemStack.EMPTY);
sendPlayerMessage(player, Component.translatable("extendedae_plus.upload_to_matrix.success"));
player.getPersistentData().putLong("eap_last_uploaded_provider_id", -999999L);
}
}

View File

@ -35,6 +35,7 @@ import java.util.UUID;
public final class ProviderUploadUtil {
private static final String PENDING_DATA_KEY = "eap_ctrlq_pending_provider_upload_id";
private static final String PENDING_STACK_KEY = "eap_ctrlq_pending_provider_upload_stack";
private static final String LAST_UPLOADED_PROVIDER_KEY = "eap_last_uploaded_provider_id";
private ProviderUploadUtil() {}
@ -114,6 +115,8 @@ public final class ProviderUploadUtil {
player.getInventory().setItem(playerSlotIndex, ItemStack.EMPTY);
}
player.getPersistentData().putLong(LAST_UPLOADED_PROVIDER_KEY, providerId);
String terminalType = PatternTerminalUtil.isExtendedAETerminal(player) ? "扩展样板管理终端" : "样板访问终端";
sendMessage(player, "ExtendedAE Plus: 通过" + terminalType + "成功上传 " + insertedCount + " 个样板");
return true;
@ -175,6 +178,7 @@ public final class ProviderUploadUtil {
} else {
encodedSlot.set(stack);
}
player.getPersistentData().putLong(LAST_UPLOADED_PROVIDER_KEY, id);
return true;
}
}
@ -227,6 +231,15 @@ public final class ProviderUploadUtil {
} else {
encodedSlot.set(stack);
}
// For index-based, we can store the negative index to let the return logic resolve it
player.getPersistentData().putLong(LAST_UPLOADED_PROVIDER_KEY, index == 0 && c == list.get(0) ? (-1L - index) : -1000000L); // store specifically if logic allows, but to be sure let's store the index format
// actually we know `c` might be from tryList, let's find the true index of `c` in `list`
int trueIndex = list.indexOf(c);
if (trueIndex >= 0) {
player.getPersistentData().putLong(LAST_UPLOADED_PROVIDER_KEY, -1L - trueIndex);
}
return true;
}
}
@ -278,6 +291,8 @@ public final class ProviderUploadUtil {
} else {
player.getPersistentData().put(PENDING_STACK_KEY, remain.save(new CompoundTag()));
}
player.getPersistentData().putLong(LAST_UPLOADED_PROVIDER_KEY, providerId);
return true;
}
@ -407,6 +422,15 @@ public final class ProviderUploadUtil {
return null;
}
public static long getLastUploadedProviderId(ServerPlayer player) {
if (player == null) return Long.MIN_VALUE;
CompoundTag data = player.getPersistentData();
if (data.contains(LAST_UPLOADED_PROVIDER_KEY)) {
return data.getLong(LAST_UPLOADED_PROVIDER_KEY);
}
return Long.MIN_VALUE;
}
/**
* ExtendedAE兼容的样板过滤器
* 使用AE2的PatternDetailsHelper进行样板验证

View File

@ -142,6 +142,7 @@
"extendedae_plus.screen.open_provider_ui": "Open the target container UI of this provider",
"extendedae_plus.button.choose_provider": "Upload Pattern",
"extendedae_plus.button.return_last_pattern": "Return Last Uploaded Pattern",
"extendedae_plus.pattern.hovertext.player": "Encoded by %s",
"item.extendedae_plus.entity_speed_ticker": "Entity Speed Ticker",

View File

@ -141,6 +141,7 @@
"extendedae_plus.screen.open_provider_ui": "打开该供应器目标容器的界面",
"extendedae_plus.button.choose_provider":"上传样板",
"extendedae_plus.button.return_last_pattern":"取回上一个上传样板",
"extendedae_plus.pattern.hovertext.player": "由 %s 编码",
"item.extendedae_plus.entity_speed_ticker": "实体加速器",

View File

@ -140,6 +140,7 @@
"extendedae_plus.screen.open_provider_ui": "開啟該供應器目標容器的介面",
"extendedae_plus.button.choose_provider": "上傳樣板",
"extendedae_plus.button.return_last_pattern": "取回上一個上傳樣板",
"extendedae_plus.pattern.hovertext.player": "由 %s 編碼",
"item.extendedae_plus.entity_speed_ticker": "實體加速器",