去除扩展供应器翻译冗余代码、优化调整

This commit is contained in:
C-H716 2025-10-29 10:09:12 +08:00
parent b7e30c057d
commit c75c2dea33
2 changed files with 23 additions and 302 deletions

View File

@ -21,24 +21,12 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@Mixin(GuiExPatternProvider.class)
public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements IExPatternButton, IExPatternPage {
@Unique
ScreenStyle eap$screenStyle;
// 跟踪上次屏幕尺寸处理 GUI 缩放/窗口大小变化后按钮丢失问题
@Unique private int eap$lastScreenWidth = -1;
@Unique private int eap$lastScreenHeight = -1;
// 不再使用右侧 VerticalButtonBar直接把按钮注册为独立 AE2 小部件
@Unique
private static final int SLOTS_PER_PAGE = 36; // 每页显示36个槽位
@Unique
private int eap$currentPage = 0;
@ -49,59 +37,16 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
super(menu, playerInventory, title, style);
}
// 移除手动挪动 Slot 坐标交由 SlotGridLayout + 原生布局控制
@Unique
private int getCurrentPage() {
@Override
public int eap$getCurrentPage() {
// 优先使用本地 GUI 维护的页码
return Math.max(0, eap$currentPage % Math.max(1, eap$maxPageLocal));
}
@Unique
private int getMaxPage() {
@Override
public int eap$getMaxPageLocal() {
// 优先使用配置倍数
try {
int cfg = ModConfig.INSTANCE.pageMultiplier;
if (cfg > 1) return cfg;
} catch (Throwable ignored) {}
try {
ContainerExPatternProvider menu1 = this.getMenu();
Field fieldMaxPage = eap$findFieldRecursive(menu1.getClass(), "maxPage");
if (fieldMaxPage != null) {
fieldMaxPage.setAccessible(true);
Object v = fieldMaxPage.get(menu1);
if (v instanceof Integer i) return i;
}
} catch (Throwable ignored) {}
// 回退用槽位总数计算
try {
int totalSlots = this.getMenu().getSlots(SlotSemantics.ENCODED_PATTERN).size();
return Math.max(1, (int) Math.ceil(totalSlots / (double) SLOTS_PER_PAGE));
} catch (Throwable ignored) {}
return 1;
}
@Unique
private static Field eap$findFieldRecursive(Class<?> cls, String name) {
Class<?> c = cls;
while (c != null && c != Object.class) {
try {
return c.getDeclaredField(name);
} catch (NoSuchFieldException ignored) {}
c = c.getSuperclass();
}
return null;
}
@Unique
private static void eap$setIntFieldRecursive(Object obj, String name, int value) {
if (obj == null) return;
Field f = eap$findFieldRecursive(obj.getClass(), name);
if (f != null) {
try { f.setAccessible(true); f.set(obj, value); } catch (Throwable ignored) {}
}
return this.eap$maxPageLocal;
}
public ActionEPPButton nextPage;
@ -116,45 +61,17 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
// 在构造器返回后初始化按钮与翻页控制
@Inject(method = "<init>", at = @At("RETURN"))
private void injectInit(ContainerExPatternProvider menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
this.eap$screenStyle = style;
// 保留不再打印菜单类型
// 计算并下发 maxPage配置优先其次按槽位总数计算
int totalSlots = this.getMenu().getSlots(SlotSemantics.ENCODED_PATTERN).size();
int cfgPages = 1;
try { cfgPages = Math.max(1, ModConfig.INSTANCE.pageMultiplier); } catch (Throwable ignored) {}
int calcPages = Math.max(1, (int) Math.ceil(totalSlots / (double) SLOTS_PER_PAGE));
int desiredMaxPage = Math.max(cfgPages, calcPages);
// 更新本地最大页
this.eap$maxPageLocal = Math.max(1, desiredMaxPage);
this.eap$currentPage = 0;
try {
Field fMax = eap$findFieldRecursive(menu.getClass(), "maxPage");
if (fMax != null) { fMax.setAccessible(true); fMax.set(menu, desiredMaxPage); }
} catch (Throwable ignored) {}
this.eap$maxPageLocal = ModConfig.INSTANCE.pageMultiplier;
// 翻页按钮当存在多页时显示支持仅由配置决定的空白页
if (desiredMaxPage > 1) {
if (eap$maxPageLocal > 1) {
this.prevPage = new ActionEPPButton((b) -> {
int currentPage = getCurrentPage();
int maxPage = Math.max(this.eap$maxPageLocal, getMaxPage());
int newPage = (currentPage - 1 + maxPage) % maxPage;
try {
ContainerExPatternProvider menu1 = this.getMenu();
// 尝试调用 setPage
try {
Method setPageMethod = menu1.getClass().getMethod("setPage", int.class);
setPageMethod.invoke(menu1, newPage);
} catch (Throwable ignored2) {}
// 直接写入 page 字段确保生效
Field f = eap$findFieldRecursive(menu1.getClass(), "page");
if (f != null) {
f.setAccessible(true);
f.set(menu1, newPage);
}
} catch (Exception ignored) {}
int currentPage = eap$getCurrentPage();
int maxPage = Math.max(this.eap$maxPageLocal, eap$getMaxPageLocal());
// 同步到本地 GUI 页码
this.eap$currentPage = newPage;
this.eap$currentPage = (currentPage - 1 + maxPage) % maxPage;
// 强制重排放在更新本地页码之后确保布局读取到新页
this.repositionSlots(SlotSemantics.ENCODED_PATTERN);
this.repositionSlots(SlotSemantics.STORAGE);
@ -162,25 +79,12 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
}, Icon.ARROW_LEFT);
this.nextPage = new ActionEPPButton((b) -> {
int currentPage = getCurrentPage();
int maxPage = Math.max(this.eap$maxPageLocal, getMaxPage());
int newPage = (currentPage + 1) % maxPage;
try {
ContainerExPatternProvider menu1 = this.getMenu();
// 尝试调用 setPage
try {
java.lang.reflect.Method setPageMethod = menu1.getClass().getMethod("setPage", int.class);
setPageMethod.invoke(menu1, newPage);
} catch (Throwable ignored2) {}
// 直接写入 page 字段确保生效
Field f = eap$findFieldRecursive(menu1.getClass(), "page");
if (f != null) {
f.setAccessible(true);
f.set(menu1, newPage);
}
} catch (Exception ignored) {}
int currentPage = eap$getCurrentPage();
int maxPage = Math.max(this.eap$maxPageLocal, eap$getMaxPageLocal());
// 同步到本地 GUI 页码
this.eap$currentPage = newPage;
this.eap$currentPage = (currentPage + 1) % maxPage;
// 强制重排放在更新本地页码之后确保布局读取到新页
this.repositionSlots(SlotSemantics.ENCODED_PATTERN);
this.repositionSlots(SlotSemantics.STORAGE);
@ -232,20 +136,6 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
this.addRenderableWidget(this.x10Button);
}
@Override
public int eap$getCurrentPage() {
return getCurrentPage();
}
@Override
public int eap$getMaxPageLocal() {
return this.eap$maxPageLocal;
}
// 页码文本绘制移交给 AEBaseScreenMixin.renderLabels 尾部执行
// 注意不再注入 Screen#init避免混入在某些映射情况下失败导致 TransformerError
@Override
public void eap$updateButtonsLayout() {
// 只处理按钮可见性与定位不再强制 showPage 或挪动 Slot 坐标避免与原布局/tooltip 冲突
@ -357,120 +247,4 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
this.x10Button.setY(by + spacing * 5);
}
}
/**
* 在服务器端执行样板缩放操作单机模式
*/
@Unique
private void executePatternScalingOnServer(net.minecraft.server.level.ServerPlayer serverPlayer, String scalingType, double scaleFactor) {
try {
// 将实际逻辑切换到服务端主线程执行避免跨线程访问导致读取到空库存
serverPlayer.getServer().execute(() -> {
try {
// 直接基于容器槽位操作完全绕开 PatternProviderLogic 及其内部字段
if (!(serverPlayer.containerMenu instanceof com.glodblock.github.extendedae.container.ContainerExPatternProvider exMenu)) {
return;
}
int scaled = 0;
int failed = 0;
int total = 0;
final int scale = (int) Math.round(scaleFactor);
final boolean div = !"MULTIPLY".equals(scalingType);
java.util.List<net.minecraft.world.inventory.Slot> slots = exMenu.getSlots(appeng.menu.SlotSemantics.ENCODED_PATTERN);
for (var slot : slots) {
var stack = slot.getItem();
if (stack.getItem() instanceof appeng.crafting.pattern.EncodedPatternItem patternItem) {
total++;
var detail = patternItem.decode(stack, serverPlayer.level(), false);
if (detail instanceof appeng.crafting.pattern.AEProcessingPattern process) {
var input = process.getSparseInputs();
var output = process.getOutputs();
// 检查是否可修改来源ExtendedAE ContainerPatternModifier.checkModify
if (checkModifyLikeExtendedAE(input, scale, div) && checkModifyLikeExtendedAE(output, scale, div)) {
var mulInput = new appeng.api.stacks.GenericStack[input.length];
var mulOutput = new appeng.api.stacks.GenericStack[output.length];
modifyStacksLikeExtendedAE(input, mulInput, scale, div);
modifyStacksLikeExtendedAE(output, mulOutput, scale, div);
var newPattern = appeng.api.crafting.PatternDetailsHelper.encodeProcessingPattern(mulInput, mulOutput);
if (slot instanceof appeng.menu.slot.AppEngSlot as) {
as.set(newPattern);
} else {
slot.set(newPattern);
}
scaled++;
} else {
failed++;
}
} else {
// 非处理样板跳过
failed++;
}
}
}
// 构造结果并回显
String message;
if (scaled == 0) {
message = String.format(
" ExtendedAE Plus: 样板%s完成但未处理任何样板。共发现 %d 个样板,失败 %d 个(可能全为合成样板或数量不满足条件)",
div ? "除法" : "倍增", total, failed);
} else if (failed > 0) {
message = String.format("✅ ExtendedAE Plus: 样板%s完成处理了 %d 个,跳过 %d 个", div ? "除法" : "倍增", scaled, failed);
} else {
message = String.format("✅ ExtendedAE Plus: 样板%s成功处理了 %d 个", div ? "除法" : "倍增", scaled);
}
var minecraft = net.minecraft.client.Minecraft.getInstance();
if (minecraft.player != null) {
minecraft.player.displayClientMessage(net.minecraft.network.chat.Component.literal(message), true);
}
} catch (Exception ignored) {
}
});
} catch (Exception ignored) {
}
}
@Unique
private boolean checkModifyLikeExtendedAE(appeng.api.stacks.GenericStack[] stacks, int scale, boolean div) {
if (div) {
for (var stack : stacks) {
if (stack != null) {
if (stack.amount() % scale != 0) {
return false;
}
}
}
} else {
for (var stack : stacks) {
if (stack != null) {
long upper = 999999L * stack.what().getAmountPerUnit();
if (stack.amount() * scale > upper) {
return false;
}
}
}
}
return true;
}
@Unique
private void modifyStacksLikeExtendedAE(appeng.api.stacks.GenericStack[] stacks,
appeng.api.stacks.GenericStack[] des,
int scale,
boolean div) {
for (int i = 0; i < stacks.length; i++) {
if (stacks[i] != null) {
long amt = div ? stacks[i].amount() / scale : stacks[i].amount() * scale;
des[i] = new appeng.api.stacks.GenericStack(stacks[i].what(), amt);
}
}
}
}

View File

@ -6,15 +6,12 @@ import appeng.crafting.pattern.AEProcessingPattern;
import appeng.crafting.pattern.EncodedPatternItem;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.SlotSemantics;
import appeng.menu.guisync.GuiSync;
import appeng.menu.implementations.PatternProviderMenu;
import appeng.menu.slot.AppEngSlot;
import com.glodblock.github.extendedae.container.ContainerExPatternProvider;
import com.glodblock.github.glodium.network.packet.sync.IActionHolder;
import com.glodblock.github.glodium.network.packet.sync.Paras;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.Slot;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@ -22,24 +19,12 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@Mixin(value = ContainerExPatternProvider.class, priority = 3000)
public abstract class ContainerExPatternProviderMixin extends PatternProviderMenu implements IActionHolder {
// 使用高位唯一ID避免与其他模组在同一类上的 @GuiSync 冲突
@GuiSync(31415)
@Unique
public int eap$page = 0;
@Unique
public int eap$maxPage = 0;
@Unique
private static final int SLOTS_PER_PAGE = 36; // 每页显示36个槽位
@Unique
private final Map<String, Consumer<Paras>> eap$actions = createHolder();
@ -47,53 +32,15 @@ public abstract class ContainerExPatternProviderMixin extends PatternProviderMen
super(menuType, id, playerInventory, host);
}
@Unique
public void eap$showPage() {
List<Slot> slots = this.getSlots(SlotSemantics.ENCODED_PATTERN);
int totalSlots = slots.size();
// 如果总槽位数不超过36个不需要翻页
if (totalSlots <= SLOTS_PER_PAGE) {
for (Slot s : slots) {
((AppEngSlot) s).setActive(true);
}
return;
}
int slot_id = 0;
for (Slot s : slots) {
int page_id = slot_id / SLOTS_PER_PAGE;
// 当前页的槽位激活
// 其他页的槽位隐藏
((AppEngSlot) s).setActive(page_id == this.eap$page);
++slot_id;
}
}
@Inject(method = "<init>", at = @At("TAIL"))
public void init(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
int maxSlots = this.getSlots(SlotSemantics.ENCODED_PATTERN).size();
this.eap$maxPage = (maxSlots + SLOTS_PER_PAGE - 1) / SLOTS_PER_PAGE;
// 注册通用动作 CGenericPacket 分发
this.eap$actions.put("multiply2", p -> { eap$modifyPatterns(2, false); });
this.eap$actions.put("divide2", p -> { eap$modifyPatterns(2, true); });
this.eap$actions.put("multiply5", p -> { eap$modifyPatterns(5, false); });
this.eap$actions.put("divide5", p -> { eap$modifyPatterns(5, true); });
this.eap$actions.put("multiply10", p -> { eap$modifyPatterns(10, false);});
this.eap$actions.put("divide10", p -> { eap$modifyPatterns(10, true); });
}
@Unique
public int getPage() {
return this.eap$page;
}
@Unique
public void setPage(int page) {
this.eap$page = page;
this.eap$actions.put("multiply2", p -> eap$modifyPatterns(2, false));
this.eap$actions.put("divide2", p -> eap$modifyPatterns(2, true));
this.eap$actions.put("multiply5", p -> eap$modifyPatterns(5, false));
this.eap$actions.put("divide5", p -> eap$modifyPatterns(5, true));
this.eap$actions.put("multiply10", p -> eap$modifyPatterns(10, false));
this.eap$actions.put("divide10", p -> eap$modifyPatterns(10, true));
}
@Unique