彻底完成样板倍增功能

This commit is contained in:
GaLi 2025-08-10 22:54:23 +08:00
parent 00fc6bad29
commit e5493eb2ca
2 changed files with 128 additions and 149 deletions

View File

@ -294,131 +294,119 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<Co
@Unique @Unique
private void executePatternScalingOnServer(net.minecraft.server.level.ServerPlayer serverPlayer, String scalingType, double scaleFactor) { private void executePatternScalingOnServer(net.minecraft.server.level.ServerPlayer serverPlayer, String scalingType, double scaleFactor) {
try { try {
// 获取服务器端的样板供应器逻辑 // 将实际逻辑切换到服务端主线程执行避免跨线程访问导致读取到空库存
appeng.helpers.patternprovider.PatternProviderLogic patternProvider = getServerSidePatternProvider(serverPlayer); serverPlayer.getServer().execute(() -> {
if (patternProvider == null) { try {
System.out.println("ExtendedAE Plus: 无法获取服务器端样板供应器"); // 直接基于容器槽位操作完全绕开 PatternProviderLogic 及其内部字段
return; if (!(serverPlayer.containerMenu instanceof com.glodblock.github.extendedae.container.ContainerExPatternProvider exMenu)) {
} System.out.println("ExtendedAE Plus: 当前容器不是 ExPatternProvider无法执行样板缩放");
return;
// 在服务器端执行样板缩放
com.extendedae_plus.util.PatternProviderDataUtil.PatternScalingResult result;
if ("MULTIPLY".equals(scalingType)) {
result = com.extendedae_plus.util.PatternProviderDataUtil.duplicatePatternAmountsExtendedAEStyle(patternProvider, scaleFactor);
} else {
result = com.extendedae_plus.util.PatternProviderDataUtil.dividePatternAmounts(patternProvider, scaleFactor);
}
// 在客户端显示结果单机模式下可以直接访问客户端
net.minecraft.client.Minecraft minecraft = net.minecraft.client.Minecraft.getInstance();
if (minecraft.player != null && result != null) {
String message;
if (result.isSuccessful()) {
if (result.getFailedPatterns() > 0) {
message = String.format("✅ ExtendedAE Plus: 样板%s成功处理了 %d 个样板,跳过 %d 个样板",
"MULTIPLY".equals(scalingType) ? "倍增" : "除法",
result.getScaledPatterns(), result.getFailedPatterns());
} else {
message = String.format("✅ ExtendedAE Plus: 样板%s成功处理了 %d 个样板",
"MULTIPLY".equals(scalingType) ? "倍增" : "除法",
result.getScaledPatterns());
} }
} else {
message = String.format("❌ ExtendedAE Plus: 样板%s失败错误: %s",
"MULTIPLY".equals(scalingType) ? "倍增" : "除法",
String.join("; ", result.getErrors()));
}
// 显示消息到动作栏 int scaled = 0;
minecraft.player.displayClientMessage(net.minecraft.network.chat.Component.literal(message), true); int failed = 0;
System.out.println("ExtendedAE Plus: " + message); int total = 0;
} final int scale = (int) Math.round(scaleFactor);
final boolean div = !"MULTIPLY".equals(scalingType);
} catch (Exception e) { java.util.List<net.minecraft.world.inventory.Slot> slots = exMenu.getSlots(appeng.menu.SlotSemantics.ENCODED_PATTERN);
System.out.println("ExtendedAE Plus: 服务器端执行样板缩放时发生错误: " + e.getMessage()); for (var slot : slots) {
e.printStackTrace(); 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];
@Unique var mulOutput = new appeng.api.stacks.GenericStack[output.length];
private appeng.helpers.patternprovider.PatternProviderLogic getServerSidePatternProvider(net.minecraft.server.level.ServerPlayer serverPlayer) { modifyStacksLikeExtendedAE(input, mulInput, scale, div);
try { modifyStacksLikeExtendedAE(output, mulOutput, scale, div);
if (serverPlayer.containerMenu != null) { var newPattern = appeng.api.crafting.PatternDetailsHelper.encodeProcessingPattern(mulInput, mulOutput);
// 检查是否是样板供应器菜单 if (slot instanceof appeng.menu.slot.AppEngSlot as) {
String menuClassName = serverPlayer.containerMenu.getClass().getSimpleName(); as.set(newPattern);
System.out.println("ExtendedAE Plus: 服务器端菜单类名: " + menuClassName); } else {
slot.set(newPattern);
if (menuClassName.contains("PatternProvider")) {
// 尝试多种可能的字段名称
String[] possibleFieldNames = {"logic", "patternProvider", "host", "provider"};
for (String fieldName : possibleFieldNames) {
try {
var field = findFieldInHierarchy(serverPlayer.containerMenu.getClass(), fieldName);
if (field != null) {
field.setAccessible(true);
Object fieldValue = field.get(serverPlayer.containerMenu);
if (fieldValue instanceof appeng.helpers.patternprovider.PatternProviderLogic) {
System.out.println("ExtendedAE Plus: 通过字段 '" + fieldName + "' 找到PatternProviderLogic");
return (appeng.helpers.patternprovider.PatternProviderLogic) fieldValue;
}
// 如果字段值是host尝试从host获取logic
if (fieldValue != null && fieldName.equals("host")) {
try {
var logicMethod = fieldValue.getClass().getMethod("getLogic");
Object logic = logicMethod.invoke(fieldValue);
if (logic instanceof appeng.helpers.patternprovider.PatternProviderLogic) {
System.out.println("ExtendedAE Plus: 通过host.getLogic()找到PatternProviderLogic");
return (appeng.helpers.patternprovider.PatternProviderLogic) logic;
}
} catch (Exception hostException) {
// 忽略host方法调用失败
} }
scaled++;
} else {
failed++;
} }
} else {
// 非处理样板跳过
failed++;
} }
} catch (Exception fieldException) {
// 继续尝试下一个字段名
} }
} }
// 如果直接字段访问失败尝试通过方法获取 // 构造结果并回显
try { String message;
var getLogicMethod = serverPlayer.containerMenu.getClass().getMethod("getLogic"); if (scaled == 0) {
Object logic = getLogicMethod.invoke(serverPlayer.containerMenu); message = String.format(
if (logic instanceof appeng.helpers.patternprovider.PatternProviderLogic) { " ExtendedAE Plus: 样板%s完成但未处理任何样板。共发现 %d 个样板,失败 %d 个(可能全为合成样板或数量不满足条件)",
System.out.println("ExtendedAE Plus: 通过getLogic()方法找到PatternProviderLogic"); div ? "除法" : "倍增", total, failed);
return (appeng.helpers.patternprovider.PatternProviderLogic) logic; } else if (failed > 0) {
} message = String.format("✅ ExtendedAE Plus: 样板%s完成处理了 %d 个,跳过 %d 个", div ? "除法" : "倍增", scaled, failed);
} catch (Exception methodException) { } 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);
}
System.out.println("ExtendedAE Plus: " + message);
} catch (Exception e) {
System.out.println("ExtendedAE Plus: 服务器端执行样板缩放时发生错误: " + e.getMessage());
e.printStackTrace();
}
});
} catch (Exception e) {
System.out.println("ExtendedAE Plus: 调度到服务器主线程时发生错误: " + e.getMessage());
e.printStackTrace();
}
}
@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;
} }
} }
} }
} catch (Exception e) { } else {
System.out.println("ExtendedAE Plus: 获取服务器端样板供应器逻辑时发生错误: " + e.getMessage()); for (var stack : stacks) {
e.printStackTrace(); if (stack != null) {
} long upper = 999999L * stack.what().getAmountPerUnit();
return null; if (stack.amount() * scale > upper) {
} return false;
}
/** }
* 在类继承层次中查找字段
*/
@Unique
private java.lang.reflect.Field findFieldInHierarchy(Class<?> clazz, String fieldName) {
Class<?> currentClass = clazz;
while (currentClass != null && currentClass != Object.class) {
try {
return currentClass.getDeclaredField(fieldName);
} catch (NoSuchFieldException e) {
currentClass = currentClass.getSuperclass();
} }
} }
return null; 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

@ -20,6 +20,7 @@ import java.util.Arrays;
* 用于获取样板供应器中的所有样板数据包括输入输出物品的数量信息 * 用于获取样板供应器中的所有样板数据包括输入输出物品的数量信息
*/ */
public class PatternProviderDataUtil { public class PatternProviderDataUtil {
private static final boolean DEBUG = true; // 临时诊断开关发布可设为 false
/** /**
* 样板数据类包含样板的输入输出信息 * 样板数据类包含样板的输入输出信息
@ -101,8 +102,9 @@ public class PatternProviderDataUtil {
* 通过检查实现类型来判断 * 通过检查实现类型来判断
*/ */
public boolean isCraftingPattern() { public boolean isCraftingPattern() {
// 根据AE2源码制作样板使用AECraftingPattern类 // 使用样板定义判断避免依赖类名发布版会被混淆
return patternDetails.getClass().getSimpleName().equals("AECraftingPattern"); String def = String.valueOf(patternDetails.getDefinition()).toLowerCase();
return def.contains("crafting");
} }
/** /**
@ -110,8 +112,9 @@ public class PatternProviderDataUtil {
* 通过检查实现类型来判断 * 通过检查实现类型来判断
*/ */
public boolean isProcessingPattern() { public boolean isProcessingPattern() {
// 处理样板使用AEProcessingPattern类 // 使用样板定义判断处理类样板含处理/石切/锻造等非合成
return patternDetails.getClass().getSimpleName().equals("AEProcessingPattern"); String def = String.valueOf(patternDetails.getDefinition()).toLowerCase();
return def.contains("processing") || def.contains("stonecutting") || def.contains("smithing");
} }
/** /**
@ -785,34 +788,23 @@ public class PatternProviderDataUtil {
*/ */
private static ItemStack scalePattern(IPatternDetails originalPattern, double scaleFactor, Level level) { private static ItemStack scalePattern(IPatternDetails originalPattern, double scaleFactor, Level level) {
try { try {
// 检查样板类型 // 基于定义字符串进行类型判断避免类名混淆问题
boolean isCraftingPattern = originalPattern.getClass().getSimpleName().equals("AECraftingPattern"); String def = String.valueOf(originalPattern.getDefinition()).toLowerCase();
boolean isProcessingPattern = originalPattern.getClass().getSimpleName().equals("AEProcessingPattern"); boolean isCrafting = def.contains("crafting");
if (isCraftingPattern) { if (isCrafting) {
// 合成样板不参与缩放直接返回null表示跳过 // 合成样板不参与缩放
return null; return null;
} else if (isProcessingPattern) {
// 如果是除法操作scaleFactor < 1需要检查是否可以除
if (scaleFactor < 1.0) {
double divisor = 1.0 / scaleFactor;
if (!canDivideProcessingPattern(originalPattern, divisor)) {
// 不能被除返回null表示跳过
return null;
}
}
// 只有处理样板才进行缩放
return scaleProcessingPattern(originalPattern, scaleFactor);
} else {
// 对于未知类型的样板也尝试作为处理样板处理
if (scaleFactor < 1.0) {
double divisor = 1.0 / scaleFactor;
if (!canDivideProcessingPattern(originalPattern, divisor)) {
return null;
}
}
return scaleProcessingPattern(originalPattern, scaleFactor);
} }
// 非合成处理/石切/锻造等按处理样板流程处理
if (scaleFactor < 1.0) {
double divisor = 1.0 / scaleFactor;
if (!canDivideProcessingPattern(originalPattern, divisor)) {
return null;
}
}
return scaleProcessingPattern(originalPattern, scaleFactor);
} catch (Exception e) { } catch (Exception e) {
return null; return null;
} }
@ -954,11 +946,10 @@ public class PatternProviderDataUtil {
*/ */
private static boolean isPatternScalable(IPatternDetails pattern) { private static boolean isPatternScalable(IPatternDetails pattern) {
if (pattern == null) return false; if (pattern == null) return false;
String def = String.valueOf(pattern.getDefinition()).toLowerCase();
String className = pattern.getClass().getSimpleName(); boolean isCrafting = def.contains("crafting");
// 只有处理样板可以缩放合成样板不支持 // 非合成且有输出认为可缩放包含处理/石切/锻造等
return "AEProcessingPattern".equals(className) || return !isCrafting && pattern.getOutputs().length > 0;
(!className.equals("AECraftingPattern") && pattern.getOutputs().length > 0);
} }
/** /**