扩展样板供应器完成

This commit is contained in:
GaLicn 2025-09-06 12:32:38 +08:00
parent d056ee43a9
commit 5ae5e7a950
6 changed files with 127 additions and 126 deletions

View File

@ -127,8 +127,10 @@ sourceSets.main.resources { srcDir 'src/generated/resources' }
//
sourceSets.main.java {
// ExtendedAE GuiExPatternProviderActionEPPButton
// CurseMaven Jar
srcDir 'othermods/ExtendedAE-1.21-2.2.21-neoforge/src/main/java'
// 广ExtendedAEPlusExtendedAEPlusClientConfig
exclude 'com/extendedae_plus/NewIcon.java'
// api/** include
include 'com/extendedae_plus/api/**'
exclude 'com/extendedae_plus/client/**'
@ -146,10 +148,16 @@ sourceSets.main.java {
include 'com/extendedae_plus/mixin/ae2/accessor/**'
// PatternProviderLogic /
include 'com/extendedae_plus/mixin/ae2/helpers/**'
// AEProcessingPattern mixin
include 'com/extendedae_plus/mixin/ae2/AEProcessingPatternMixin.java'
// GUI A GUI
include 'com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java'
include 'com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java'
include 'com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java'
// ExtendedAE GUI NewIcon
// Provider GUI 使广 exclude include
include 'com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java'
include 'com/extendedae_plus/NewIcon.java'
// network/** include
// util
include 'com/extendedae_plus/util/PatternProviderDataUtil.java'
@ -161,6 +169,7 @@ sourceSets.main.java {
include 'com/extendedae_plus/network/ModNetwork.java'
include 'com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java'
include 'com/extendedae_plus/network/ToggleSmartDoublingC2SPacket.java'
include 'com/extendedae_plus/network/ScalePatternsC2SPacket.java'
// include util util/**
include 'com/extendedae_plus/util/PatternProviderDataUtil.java'
include 'com/extendedae_plus/util/PatternProviderUIHelper.java'
@ -205,9 +214,9 @@ dependencies {
implementation "org.appliedenergistics:guideme:2.5.1"
// jarJar configuration not set in this build; use implementation for API for now
implementation "de.mari_023:ae2wtlib_api:19.2.0"
implementation "curse.maven:ex-pattern-provider-892005:6863556"
implementation "curse.maven:curios-309927:6529130"
compileOnly "curse.maven:ex-pattern-provider-892005:6863556"
compileOnly "curse.maven:applied-flux-965012:5614830"
compileOnly "dev.emi:emi-neoforge:1.1.10+1.21"
compileOnly "curse.maven:mega-cells-622112:6005043"
@ -229,6 +238,7 @@ dependencies {
runtimeOnly "curse.maven:jade-324717:5427817"
runtimeOnly "curse.maven:mega-cells-622112:6005043"
runtimeOnly "mekanism:Mekanism:1.21.1-10.7.0.55"
runtimeOnly "curse.maven:ex-pattern-provider-892005:6863556"
// setup Xei (EMI/REI/JEI) using project property 'use_Xei'
switch (project.findProperty('use_Xei') ?: 'emi') {

View File

@ -5,7 +5,9 @@ import net.minecraft.resources.ResourceLocation;
public class NewIcon {
@SuppressWarnings("all")
private static final ResourceLocation TEXTURE = new ResourceLocation(ExtendedAEPlus.MODID,"textures/gui/nicons.png");
// 贴图当前存放于 assets/extendedae_plus/textures/gui/nicons.png
// MODID (extendedaeplus) 不同因此这里直接指定贴图所在命名空间
private static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath("extendedae_plus", "textures/gui/nicons.png");

View File

@ -10,9 +10,9 @@ import com.extendedae_plus.config.ModConfigs;
import com.glodblock.github.extendedae.client.button.ActionEPPButton;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import com.glodblock.github.extendedae.container.ContainerExPatternProvider;
import com.glodblock.github.extendedae.network.EPPNetworkHandler;
import com.glodblock.github.glodium.network.packet.CGenericPacket;
import net.minecraft.network.chat.Component;
import net.minecraft.client.Minecraft;
import com.extendedae_plus.network.ScalePatternsC2SPacket;
import net.minecraft.world.entity.player.Inventory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@ -196,34 +196,40 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
this.addToLeftToolbar(this.prevPage);
}
// 倍增/除法按钮通过 ExtendedAE 的通用包派发
// 倍增/除法按钮使用自有 C2S 包发送到服务端执行样板缩放
this.x2Button = new ActionEPPButton((b) -> {
EPPNetworkHandler.INSTANCE.sendToServer(new CGenericPacket("multiply2"));
var conn = Minecraft.getInstance().getConnection();
if (conn != null) conn.send(new ScalePatternsC2SPacket(ScalePatternsC2SPacket.Operation.MUL2));
}, NewIcon.MULTIPLY2);
this.x2Button.setVisibility(true);
this.divideBy2Button = new ActionEPPButton((b) -> {
EPPNetworkHandler.INSTANCE.sendToServer(new CGenericPacket("divide2"));
var conn = Minecraft.getInstance().getConnection();
if (conn != null) conn.send(new ScalePatternsC2SPacket(ScalePatternsC2SPacket.Operation.DIV2));
}, NewIcon.DIVIDE2);
this.divideBy2Button.setVisibility(true);
this.x10Button = new ActionEPPButton((b) -> {
EPPNetworkHandler.INSTANCE.sendToServer(new CGenericPacket("multiply10"));
var conn = Minecraft.getInstance().getConnection();
if (conn != null) conn.send(new ScalePatternsC2SPacket(ScalePatternsC2SPacket.Operation.MUL10));
}, NewIcon.MULTIPLY10);
this.x10Button.setVisibility(true);
this.divideBy10Button = new ActionEPPButton((b) -> {
EPPNetworkHandler.INSTANCE.sendToServer(new CGenericPacket("divide10"));
var conn = Minecraft.getInstance().getConnection();
if (conn != null) conn.send(new ScalePatternsC2SPacket(ScalePatternsC2SPacket.Operation.DIV10));
}, NewIcon.DIVIDE10);
this.divideBy10Button.setVisibility(true);
this.divideBy5Button = new ActionEPPButton((b) -> {
EPPNetworkHandler.INSTANCE.sendToServer(new CGenericPacket("divide5"));
var conn = Minecraft.getInstance().getConnection();
if (conn != null) conn.send(new ScalePatternsC2SPacket(ScalePatternsC2SPacket.Operation.DIV5));
}, NewIcon.DIVIDE5);
this.divideBy5Button.setVisibility(true);
this.x5Button = new ActionEPPButton((b) -> {
EPPNetworkHandler.INSTANCE.sendToServer(new CGenericPacket("multiply5"));
var conn = Minecraft.getInstance().getConnection();
if (conn != null) conn.send(new ScalePatternsC2SPacket(ScalePatternsC2SPacket.Operation.MUL5));
}, NewIcon.MULTIPLY5);
this.x5Button.setVisibility(true);
@ -357,119 +363,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
}
}
/**
* 在服务器端执行样板缩放操作单机模式
*/
@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);
}
}
}
// 本文件原包含本地样板缩放实现单机模式 ExtendedAE 网络派发已移除以兼容 1.21.1 与最小可构建集
}

View File

@ -9,5 +9,6 @@ public class ModNetwork {
var registrar = event.registrar(ExtendedAEPlus.MODID);
registrar.playToServer(ToggleAdvancedBlockingC2SPacket.TYPE, ToggleAdvancedBlockingC2SPacket.STREAM_CODEC, ToggleAdvancedBlockingC2SPacket::handle);
registrar.playToServer(ToggleSmartDoublingC2SPacket.TYPE, ToggleSmartDoublingC2SPacket.STREAM_CODEC, ToggleSmartDoublingC2SPacket::handle);
registrar.playToServer(ScalePatternsC2SPacket.TYPE, ScalePatternsC2SPacket.STREAM_CODEC, ScalePatternsC2SPacket::handle);
}
}

View File

@ -0,0 +1,91 @@
package com.extendedae_plus.network;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.util.PatternProviderDataUtil;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.network.handling.IPayloadContext;
/**
* C2S请求对当前打开的样板供应器执行样板数量缩放倍增或除法
*/
public class ScalePatternsC2SPacket implements CustomPacketPayload {
public enum Operation {
MUL2, DIV2, MUL5, DIV5, MUL10, DIV10
}
public static final Type<ScalePatternsC2SPacket> TYPE = new Type<>(
ResourceLocation.fromNamespaceAndPath(ExtendedAEPlus.MODID, "scale_patterns"));
public static final StreamCodec<FriendlyByteBuf, ScalePatternsC2SPacket> STREAM_CODEC = StreamCodec.of(
(buf, pkt) -> buf.writeEnum(pkt.op),
buf -> new ScalePatternsC2SPacket(buf.readEnum(Operation.class))
);
private final Operation op;
public ScalePatternsC2SPacket(Operation op) {
this.op = op;
}
public Operation op() {
return op;
}
@Override
public Type<? extends CustomPacketPayload> type() {
return TYPE;
}
public static void handle(final ScalePatternsC2SPacket msg, final IPayloadContext ctx) {
ctx.enqueueWork(() -> {
if (!(ctx.player() instanceof ServerPlayer player)) return;
if (!(player.containerMenu instanceof PatternProviderMenu menu)) return;
try {
var accessor = (PatternProviderMenuAdvancedAccessor) menu;
PatternProviderLogic logic = accessor.eap$logic();
if (logic == null) return;
double factor;
boolean multiply;
switch (msg.op) {
case MUL2 -> { factor = 2.0; multiply = true; }
case DIV2 -> { factor = 2.0; multiply = false; }
case MUL5 -> { factor = 5.0; multiply = true; }
case DIV5 -> { factor = 5.0; multiply = false; }
case MUL10 -> { factor = 10.0; multiply = true; }
case DIV10 -> { factor = 10.0; multiply = false; }
default -> { return; }
}
PatternProviderDataUtil.PatternScalingResult result;
if (multiply) {
result = PatternProviderDataUtil.multiplyPatternAmounts(logic, factor);
} else {
result = PatternProviderDataUtil.dividePatternAmounts(logic, factor);
}
logic.saveChanges();
// 回显结果到玩家
String summary = String.format("样板缩放(%s x%.0f): 共%d, 成功%d, 失败%d", multiply ? "倍增" : "除法",
factor, result.getTotalPatterns(), result.getScaledPatterns(), result.getFailedPatterns());
player.displayClientMessage(net.minecraft.network.chat.Component.literal("[EAP] " + summary), true);
for (String err : result.getErrors()) {
ExtendedAELogger.LOGGER.debug("[EAP] scale error: {}", err);
}
} catch (Throwable t) {
ExtendedAELogger.LOGGER.error("[EAP] Handle ScalePatternsC2SPacket failed", t);
}
});
}
}

View File

@ -4,12 +4,15 @@
"compatibilityLevel": "JAVA_21",
"mixins": [
"ae2.accessor.PatternProviderLogicAccessor",
"ae2.accessor.PatternProviderLogicPatternsAccessor",
"ae2.accessor.PatternProviderMenuAdvancedAccessor",
"ae2.client.gui.PatternProviderScreenMixin",
"ae2.menu.PatternProviderMenuAdvancedMixin",
"ae2.menu.PatternProviderMenuDoublingMixin",
"ae2.helpers.PatternProviderLogicAdvancedMixin",
"ae2.helpers.PatternProviderLogicDoublingMixin"
"ae2.helpers.PatternProviderLogicDoublingMixin",
"ae2.AEProcessingPatternMixin",
"extendedae.client.gui.GuiExPatternProviderMixin"
],
"injectors": {
"defaultRequire": 1