1.搭建gtl环境,其中resourcefullib不能换。
2.兼容147版本eae的高亮聊天文本提示 3.修复扩展样板管理终端UI按钮在eae147版本失效问题
This commit is contained in:
parent
bb6704d830
commit
a3bd163cb6
38
build.gradle
38
build.gradle
|
|
@ -60,6 +60,15 @@ repositories {
|
|||
}
|
||||
maven { url "https://repo.spongepowered.org/maven" }
|
||||
maven { url "https://dl.cloudsmith.io/public/geckolib3/geckolib/maven/" }
|
||||
maven { // Registrate
|
||||
url = "https://maven.tterrag.com/"
|
||||
content {
|
||||
// need to be specific here due to version overlaps
|
||||
includeGroup("com.jozufozu.flywheel")
|
||||
includeGroup("com.tterrag.registrate")
|
||||
includeGroup("com.simibubi.create")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
|
@ -70,7 +79,7 @@ dependencies {
|
|||
//exendedae前置
|
||||
modImplementation "curse.maven:glodium-957920:${glodium_version}"
|
||||
//extendedAE
|
||||
modImplementation files('libs/ExtendedAE-1.20-1.4.2-forge.jar')
|
||||
modImplementation files('libs/ExtendedAE-1.20-1.4.7-forge.jar')
|
||||
modRuntimeOnly fileTree(dir: 'libs', includes: ['*.jar'])
|
||||
|
||||
//ae2
|
||||
|
|
@ -87,9 +96,19 @@ dependencies {
|
|||
modCompileOnly "curse.maven:jade-324717:${jade_version}"
|
||||
|
||||
// GregTech
|
||||
modCompileOnly "curse.maven:gregtechceu-modern-890405:${gregtech_version}"
|
||||
modCompileOnly "curse.maven:ldlib-626676:${ldlib_version}"
|
||||
modCompileOnly files('libs/gtlcore-1.2.2.3-fix6.jar')
|
||||
modImplementation "curse.maven:gregtechceu-modern-890405:${gregtech_version}"
|
||||
modImplementation "curse.maven:ldlib-626676:5775541"
|
||||
modImplementation files('libs/gtlcore-1.2.2.4-fix8.jar')
|
||||
modImplementation("dev:gtmthings-1.3.5.b")
|
||||
modImplementation("dev:resourcefullib-forge-1.20.1-2.1.29")
|
||||
modImplementation("dev:resourcefulconfig-forge-1.20.1-2.1.3")
|
||||
modImplementation("dev:botarium-forge-1.20.1-2.3.4")
|
||||
modImplementation("dev:ad_astra-forge-1.20.1-1.15.20")
|
||||
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.2.0"))
|
||||
implementation(include("io.github.llamalad7:mixinextras-forge:0.2.0"))
|
||||
modImplementation("com.tterrag.registrate:Registrate:MC1.20-1.3.11")
|
||||
modImplementation("curse.maven:kubejs-238086:5454840")
|
||||
modImplementation("curse.maven:rhino-416294:6186971")
|
||||
|
||||
//curios
|
||||
modRuntimeOnly "curse.maven:curios-309927:${curios_version}"
|
||||
|
|
@ -97,7 +116,7 @@ dependencies {
|
|||
|
||||
// Runtime test
|
||||
modRuntimeOnly "curse.maven:curios-309927:${curios_version}"
|
||||
modRuntimeOnly "curse.maven:jade-324717:${jade_version}"
|
||||
modImplementation "curse.maven:jade-324717:5339264"
|
||||
modRuntimeOnly "curse.maven:architectury-api-419699:${architectury_version}"
|
||||
modRuntimeOnly "curse.maven:applied-energistics-2-wireless-terminals-459929:${wireless_terminals_version}"
|
||||
modRuntimeOnly "mezz.jei:jei-${minecraft_version}-forge:${jei_version}"
|
||||
|
|
@ -106,9 +125,14 @@ dependencies {
|
|||
//jec
|
||||
modCompileOnly "curse.maven:just-enough-characters-250702:6680042"
|
||||
|
||||
//拼音搜索
|
||||
modRuntimeOnly("dev:jecharacters-1.20.1-forge-4.5.11-dev-shadow")
|
||||
//输入法冲突
|
||||
modRuntimeOnly("curse.maven:cloth-config-348521:5729105")
|
||||
modRuntimeOnly("curse.maven:IMBlocker-483760:6922546")
|
||||
|
||||
//mae2
|
||||
// modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
||||
// modRuntimeOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
||||
modCompileOnly "curse.maven:modern-ae2-additions-1028068:6827727"
|
||||
|
||||
//aea
|
||||
|
|
@ -126,8 +150,10 @@ dependencies {
|
|||
//ftbteams
|
||||
modCompileOnly "curse.maven:ftb-teams-forge-404468:6130786"
|
||||
modCompileOnly "curse.maven:ftb-library-forge-404465:6807424"
|
||||
modCompileOnly "curse.maven:ftb-chunk-forge-314906:6431735"
|
||||
modRuntimeOnly "curse.maven:ftb-teams-forge-404468:6130786"
|
||||
modRuntimeOnly "curse.maven:ftb-library-forge-404465:6807424"
|
||||
modRuntimeOnly "curse.maven:ftb-chunk-forge-314906:6431735"
|
||||
}
|
||||
|
||||
compileJava {
|
||||
|
|
|
|||
Binary file not shown.
BIN
libs/ExtendedAE-1.20-1.4.7-forge.jar
Normal file
BIN
libs/ExtendedAE-1.20-1.4.7-forge.jar
Normal file
Binary file not shown.
BIN
libs/ad_astra-forge-1.20.1-1.15.20.jar
Normal file
BIN
libs/ad_astra-forge-1.20.1-1.15.20.jar
Normal file
Binary file not shown.
BIN
libs/botarium-forge-1.20.1-2.3.4.jar
Normal file
BIN
libs/botarium-forge-1.20.1-2.3.4.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
libs/gtmthings-1.3.5.b.jar
Normal file
BIN
libs/gtmthings-1.3.5.b.jar
Normal file
Binary file not shown.
BIN
libs/jecharacters-1.20.1-forge-4.5.11-dev-shadow.jar
Normal file
BIN
libs/jecharacters-1.20.1-forge-4.5.11-dev-shadow.jar
Normal file
Binary file not shown.
BIN
libs/resourcefulconfig-forge-1.20.1-2.1.3.jar
Normal file
BIN
libs/resourcefulconfig-forge-1.20.1-2.1.3.jar
Normal file
Binary file not shown.
BIN
libs/resourcefullib-forge-1.20.1-2.1.29.jar
Normal file
BIN
libs/resourcefullib-forge-1.20.1-2.1.29.jar
Normal file
Binary file not shown.
|
|
@ -67,10 +67,14 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
|
||||
@Unique
|
||||
private boolean eap$debugLoggedOnce = false;
|
||||
@Shadow(remap = false) private AETextField searchOutField;
|
||||
@Shadow(remap = false) private AETextField searchInField;
|
||||
@Shadow(remap = false) private Set<ItemStack> matchedStack;
|
||||
@Shadow(remap = false) private Set<PatternContainerRecord> matchedProvider;
|
||||
@Shadow(remap = false)
|
||||
private AETextField searchOutField;
|
||||
@Shadow(remap = false)
|
||||
private AETextField searchInField;
|
||||
@Shadow(remap = false)
|
||||
private Set<ItemStack> matchedStack;
|
||||
@Shadow(remap = false)
|
||||
private Set<PatternContainerRecord> matchedProvider;
|
||||
|
||||
public GuiExPatternTerminalMixin(AEBaseMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
|
||||
super(menu, playerInventory, title, style);
|
||||
|
|
@ -137,13 +141,15 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
private void eap$quickUploadPattern(int playerSlotIndex) {
|
||||
if (this.minecraft.player != null) {
|
||||
// 获取要上传的物品
|
||||
ItemStack itemToUpload = this.minecraft.player.getInventory().getItem(playerSlotIndex);
|
||||
ItemStack itemToUpload = this.minecraft.player.getInventory()
|
||||
.getItem(playerSlotIndex);
|
||||
|
||||
if (!itemToUpload.isEmpty() && PatternDetailsHelper.isEncodedPattern(itemToUpload)) {
|
||||
// 通过反射调用 ExtendedAE 的网络发送(软依赖)
|
||||
try {
|
||||
Class<?> EPPNetworkHandlerClass = Class.forName("com.glodblock.github.extendedae.network.EPPNetworkHandler");
|
||||
Object handlerInstance = EPPNetworkHandlerClass.getField("INSTANCE").get(null);
|
||||
Object handlerInstance = EPPNetworkHandlerClass.getField("INSTANCE")
|
||||
.get(null);
|
||||
|
||||
Class<?> packetClass = Class.forName("com.glodblock.github.glodium.network.packet.CGenericPacket");
|
||||
Constructor<?> constructor = packetClass.getConstructor(String.class, Object[].class);
|
||||
|
|
@ -193,17 +199,23 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
Object byGroup = byGroupField.get(this); // HashMultimap<PatternContainerGroup, PatternContainerRecord>
|
||||
|
||||
Object headerRow = rows.get(rowIndex);
|
||||
var groupField = headerRow.getClass().getDeclaredField("group");
|
||||
var groupField = headerRow.getClass()
|
||||
.getDeclaredField("group");
|
||||
groupField.setAccessible(true);
|
||||
Object group = groupField.get(headerRow);
|
||||
|
||||
// 调用 byGroup.get(group),再取第一个元素
|
||||
Collection<?> containers = (Collection<?>) byGroup.getClass().getMethod("get", Object.class).invoke(byGroup, group);
|
||||
Collection<?> containers = (Collection<?>) byGroup.getClass()
|
||||
.getMethod("get", Object.class)
|
||||
.invoke(byGroup, group);
|
||||
if (containers == null || containers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Object firstRecord = containers.iterator().next(); // PatternContainerRecord
|
||||
long serverId = (long) firstRecord.getClass().getMethod("getServerId").invoke(firstRecord);
|
||||
Object firstRecord = containers.iterator()
|
||||
.next(); // PatternContainerRecord
|
||||
long serverId = (long) firstRecord.getClass()
|
||||
.getMethod("getServerId")
|
||||
.invoke(firstRecord);
|
||||
|
||||
// 通过 infoMap 获取位置信息
|
||||
var infoMapField = cls.getDeclaredField("infoMap");
|
||||
|
|
@ -220,13 +232,28 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
}
|
||||
|
||||
// PatternProviderInfo record: pos(), face(), playerWorld()
|
||||
Object pos = info.getClass().getMethod("pos").invoke(info);
|
||||
Object face = info.getClass().getMethod("face").invoke(info); // 可能为 null(方块型供应器)
|
||||
Object playerWorld = info.getClass().getMethod("playerWorld").invoke(info);
|
||||
Object pos = info.getClass()
|
||||
.getMethod("pos")
|
||||
.invoke(info);
|
||||
Object face = info.getClass()
|
||||
.getMethod("face")
|
||||
.invoke(info); // 可能为 null(方块型供应器)
|
||||
Object playerWorld;
|
||||
try {
|
||||
playerWorld = info.getClass()
|
||||
.getMethod("playerWorld")
|
||||
.invoke(info);
|
||||
} catch (Throwable t) {
|
||||
playerWorld = info.getClass()
|
||||
.getMethod("world")
|
||||
.invoke(info);
|
||||
}
|
||||
|
||||
|
||||
// 避免对 MC 类进行反射,使用强制类型转换后直接调用方法(由 Forge 运行时重映射保证)
|
||||
long posLong = ((BlockPos) pos).asLong();
|
||||
String dimStr = ((ResourceKey<Level>) playerWorld).location().toString();
|
||||
String dimStr = ((ResourceKey<Level>) playerWorld).location()
|
||||
.toString();
|
||||
int faceOrd = -1;
|
||||
if (face != null) {
|
||||
faceOrd = ((Direction) face).ordinal();
|
||||
|
|
@ -271,11 +298,14 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
Method refreshMethod = null;
|
||||
try {
|
||||
// 先尝试在当前类中查找
|
||||
refreshMethod = this.getClass().getDeclaredMethod("refreshList");
|
||||
refreshMethod = this.getClass()
|
||||
.getDeclaredMethod("refreshList");
|
||||
} catch (NoSuchMethodException e1) {
|
||||
// 如果当前类没有,尝试在父类中查找
|
||||
try {
|
||||
refreshMethod = this.getClass().getSuperclass().getDeclaredMethod("refreshList");
|
||||
refreshMethod = this.getClass()
|
||||
.getSuperclass()
|
||||
.getDeclaredMethod("refreshList");
|
||||
} catch (NoSuchMethodException e2) {
|
||||
throw e2;
|
||||
}
|
||||
|
|
@ -309,17 +339,21 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
private void eap$onResize(Minecraft mc, int width, int height, CallbackInfo ci) {
|
||||
try {
|
||||
// 移除并清理按钮,避免旧位置残留
|
||||
this.eap$openUIButtons.values().forEach(this::removeWidget);
|
||||
this.eap$openUIButtons.values()
|
||||
.forEach(this::removeWidget);
|
||||
this.eap$openUIButtons.clear();
|
||||
|
||||
// 重置一次滚动条,避免可见行/偏移在缩放后与 UI 尺寸不一致
|
||||
try {
|
||||
Method resetScrollbarMethod = null;
|
||||
try {
|
||||
resetScrollbarMethod = this.getClass().getDeclaredMethod("resetScrollbar");
|
||||
resetScrollbarMethod = this.getClass()
|
||||
.getDeclaredMethod("resetScrollbar");
|
||||
} catch (NoSuchMethodException e1) {
|
||||
try {
|
||||
resetScrollbarMethod = this.getClass().getSuperclass().getDeclaredMethod("resetScrollbar");
|
||||
resetScrollbarMethod = this.getClass()
|
||||
.getSuperclass()
|
||||
.getDeclaredMethod("resetScrollbar");
|
||||
} catch (NoSuchMethodException e2) {
|
||||
resetScrollbarMethod = null;
|
||||
}
|
||||
|
|
@ -335,10 +369,13 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
try {
|
||||
Method refreshMethod = null;
|
||||
try {
|
||||
refreshMethod = this.getClass().getDeclaredMethod("refreshList");
|
||||
refreshMethod = this.getClass()
|
||||
.getDeclaredMethod("refreshList");
|
||||
} catch (NoSuchMethodException e1) {
|
||||
try {
|
||||
refreshMethod = this.getClass().getSuperclass().getDeclaredMethod("refreshList");
|
||||
refreshMethod = this.getClass()
|
||||
.getSuperclass()
|
||||
.getDeclaredMethod("refreshList");
|
||||
} catch (NoSuchMethodException e2) {
|
||||
refreshMethod = null;
|
||||
}
|
||||
|
|
@ -359,7 +396,8 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
@Inject(method = "init", at = @At("TAIL"), remap = false, require = 0)
|
||||
private void eap$onInit(CallbackInfo ci) {
|
||||
// 清理旧的打开UI按钮
|
||||
this.eap$openUIButtons.values().forEach(this::removeWidget);
|
||||
this.eap$openUIButtons.values()
|
||||
.forEach(this::removeWidget);
|
||||
this.eap$openUIButtons.clear();
|
||||
}
|
||||
|
||||
|
|
@ -372,7 +410,8 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
)));
|
||||
}
|
||||
// 清理旧的打开UI按钮
|
||||
this.eap$openUIButtons.values().forEach(this::removeWidget);
|
||||
this.eap$openUIButtons.values()
|
||||
.forEach(this::removeWidget);
|
||||
this.eap$openUIButtons.clear();
|
||||
}
|
||||
|
||||
|
|
@ -386,11 +425,14 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
java.lang.reflect.Field rowsField = null;
|
||||
try {
|
||||
// 先尝试在当前类中查找
|
||||
rowsField = this.getClass().getDeclaredField("rows");
|
||||
rowsField = this.getClass()
|
||||
.getDeclaredField("rows");
|
||||
} catch (NoSuchFieldException e1) {
|
||||
// 如果当前类没有,尝试在父类中查找
|
||||
try {
|
||||
rowsField = this.getClass().getSuperclass().getDeclaredField("rows");
|
||||
rowsField = this.getClass()
|
||||
.getSuperclass()
|
||||
.getDeclaredField("rows");
|
||||
} catch (NoSuchFieldException e2) {
|
||||
throw e2;
|
||||
}
|
||||
|
|
@ -402,11 +444,14 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
java.lang.reflect.Field highlightBtnsField = null;
|
||||
try {
|
||||
// 先尝试在当前类中查找
|
||||
highlightBtnsField = this.getClass().getDeclaredField("highlightBtns");
|
||||
highlightBtnsField = this.getClass()
|
||||
.getDeclaredField("highlightBtns");
|
||||
} catch (NoSuchFieldException e1) {
|
||||
// 如果当前类没有,尝试在父类中查找
|
||||
try {
|
||||
highlightBtnsField = this.getClass().getSuperclass().getDeclaredField("highlightBtns");
|
||||
highlightBtnsField = this.getClass()
|
||||
.getSuperclass()
|
||||
.getDeclaredField("highlightBtns");
|
||||
} catch (NoSuchFieldException e2) {
|
||||
throw e2;
|
||||
}
|
||||
|
|
@ -422,7 +467,8 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
// 移除所有SlotsRow,只保留GroupHeaderRow,同时重新映射高亮按钮索引
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
Object row = rows.get(i);
|
||||
String className = row.getClass().getSimpleName();
|
||||
String className = row.getClass()
|
||||
.getSimpleName();
|
||||
|
||||
if (className.equals("GroupHeaderRow")) {
|
||||
// 保留GroupHeaderRow,并重新映射对应的高亮按钮
|
||||
|
|
@ -459,11 +505,14 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
Method resetScrollbarMethod = null;
|
||||
try {
|
||||
// 先尝试在当前类中查找
|
||||
resetScrollbarMethod = this.getClass().getDeclaredMethod("resetScrollbar");
|
||||
resetScrollbarMethod = this.getClass()
|
||||
.getDeclaredMethod("resetScrollbar");
|
||||
} catch (NoSuchMethodException e1) {
|
||||
// 如果当前类没有,尝试在父类中查找
|
||||
try {
|
||||
resetScrollbarMethod = this.getClass().getSuperclass().getDeclaredMethod("resetScrollbar");
|
||||
resetScrollbarMethod = this.getClass()
|
||||
.getSuperclass()
|
||||
.getDeclaredMethod("resetScrollbar");
|
||||
} catch (NoSuchMethodException e2) {
|
||||
throw e2;
|
||||
}
|
||||
|
|
@ -485,7 +534,8 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
// 使用 Accessor 获取必要的字段,避免反射失败
|
||||
GuiExPatternTerminalAccessor acc = (GuiExPatternTerminalAccessor) this;
|
||||
java.util.ArrayList<?> rows = acc.getRows();
|
||||
int currentScroll = acc.getScrollbar().getCurrentScroll();
|
||||
int currentScroll = acc.getScrollbar()
|
||||
.getCurrentScroll();
|
||||
|
||||
// 直接引用目标类以获取其静态常量
|
||||
Class<?> cls = GuiExPatternTerminal.class;
|
||||
|
|
@ -511,7 +561,9 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
continue;
|
||||
}
|
||||
Object row = rows.get(rowIndex);
|
||||
if (!row.getClass().getSimpleName().equals("GroupHeaderRow")) {
|
||||
if (!row.getClass()
|
||||
.getSimpleName()
|
||||
.equals("GroupHeaderRow")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -522,8 +574,10 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
Button btn = eap$openUIButtons.get(rowIndex);
|
||||
if (btn == null) {
|
||||
btn = Button.builder(Component.literal("UI"), (b) -> {
|
||||
eap$tryOpenProviderUI(rowIndex);
|
||||
}).size(14, 12).build();
|
||||
eap$tryOpenProviderUI(rowIndex);
|
||||
})
|
||||
.size(14, 12)
|
||||
.build();
|
||||
btn.setTooltip(Tooltip.create(Component.literal("打开该供应器目标容器的界面")));
|
||||
eap$openUIButtons.put(rowIndex, btn);
|
||||
this.addRenderableWidget(btn);
|
||||
|
|
@ -538,8 +592,10 @@ public abstract class GuiExPatternTerminalMixin extends AEBaseScreen<AEBaseMenu>
|
|||
|
||||
// 原有的搜索高亮逻辑
|
||||
// 仅当任一搜索框非空时绘制叠加层(与原版行为保持一致)
|
||||
boolean searchActive = (this.searchOutField != null && !this.searchOutField.getValue().isEmpty())
|
||||
|| (this.searchInField != null && !this.searchInField.getValue().isEmpty());
|
||||
boolean searchActive = (this.searchOutField != null && !this.searchOutField.getValue()
|
||||
.isEmpty())
|
||||
|| (this.searchInField != null && !this.searchInField.getValue()
|
||||
.isEmpty());
|
||||
if (!searchActive) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,207 +0,0 @@
|
|||
package com.extendedae_plus.network;
|
||||
|
||||
import appeng.api.crafting.IPatternDetails;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.security.IActionHost;
|
||||
import appeng.api.stacks.AEKey;
|
||||
import appeng.helpers.patternprovider.PatternProviderLogic;
|
||||
import appeng.helpers.patternprovider.PatternProviderLogicHost;
|
||||
import appeng.me.service.CraftingService;
|
||||
import appeng.menu.AEBaseMenu;
|
||||
import appeng.menu.locator.MenuLocators;
|
||||
import appeng.menu.me.crafting.CraftingCPUMenu;
|
||||
import appeng.parts.AEBasePart;
|
||||
import com.extendedae_plus.init.ModNetwork;
|
||||
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
|
||||
import com.extendedae_plus.network.provider.SetProviderPageS2CPacket;
|
||||
import com.extendedae_plus.util.PatternProviderDataUtil;
|
||||
import com.glodblock.github.extendedae.util.FCClientUtil;
|
||||
import com.glodblock.github.glodium.util.GlodUtil;
|
||||
import com.gregtechceu.gtceu.api.gui.factory.MachineUIFactory;
|
||||
import com.gregtechceu.gtceu.api.machine.MetaMachine;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.glodblock.github.extendedae.client.render.EAEHighlightHandler.highlight;
|
||||
|
||||
/**
|
||||
* 客户端从 CraftingCPUScreen 发送:鼠标下条目对应的 AEKey。
|
||||
* 服务端在当前打开的 CraftingCPUMenu 所属网络中,定位匹配该 AEKey 的样板供应器,
|
||||
* 打开该供应器自身的 UI(不是目标机器的 UI)。
|
||||
*/
|
||||
public class CraftingMonitorOpenProviderC2SPacket {
|
||||
private final AEKey what;
|
||||
|
||||
public CraftingMonitorOpenProviderC2SPacket(AEKey what) {
|
||||
this.what = what;
|
||||
}
|
||||
|
||||
public static void encode(CraftingMonitorOpenProviderC2SPacket msg, FriendlyByteBuf buf) {
|
||||
AEKey.writeKey(buf, msg.what);
|
||||
}
|
||||
|
||||
public static CraftingMonitorOpenProviderC2SPacket decode(FriendlyByteBuf buf) {
|
||||
AEKey key = AEKey.readKey(buf);
|
||||
return new CraftingMonitorOpenProviderC2SPacket(key);
|
||||
}
|
||||
|
||||
public static void handle(CraftingMonitorOpenProviderC2SPacket msg, Supplier<NetworkEvent.Context> ctx) {
|
||||
NetworkEvent.Context context = ctx.get();
|
||||
context.enqueueWork(() -> {
|
||||
ServerPlayer player = context.getSender();
|
||||
if (player == null) return;
|
||||
|
||||
// 必须在 CraftingCPU 界面内
|
||||
if (!(player.containerMenu instanceof CraftingCPUMenu menu)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 通过菜单的 target(可能是 BlockEntity/Part/ItemHost),按 IActionHost 获取 Grid
|
||||
IGrid grid = null;
|
||||
Object target = ((AEBaseMenu) menu).getTarget();
|
||||
if (target instanceof IActionHost host && host.getActionableNode() != null) {
|
||||
grid = host.getActionableNode().getGrid();
|
||||
}
|
||||
if (grid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var cs = grid.getCraftingService();
|
||||
if (!(cs instanceof CraftingService craftingService)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 1) 根据 AEKey 找到可能的样板(pattern)
|
||||
Collection<IPatternDetails> patterns = craftingService.getCraftingFor(msg.what);
|
||||
if (patterns.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 2) 遍历提供该样板的 Provider,定位 PatternProviderLogic
|
||||
for (var pattern : patterns) {
|
||||
var providers = craftingService.getProviders(pattern);
|
||||
for (var provider : providers) {
|
||||
if (provider instanceof PatternProviderLogic ppl) {
|
||||
// accessor 获取 host
|
||||
PatternProviderLogicHost host = ((PatternProviderLogicAccessor) ppl).eap$host();
|
||||
if (host == null) continue;
|
||||
var pbe = host.getBlockEntity();
|
||||
if (pbe == null) continue;
|
||||
|
||||
// 跳过未连接到网格或不活跃的 provider(使用 util 判断并传入当前 grid)
|
||||
if (!PatternProviderDataUtil.isProviderAvailable(ppl, grid)) continue;
|
||||
|
||||
// 直接打开供应器自身的 UI(调用 Host 默认方法)
|
||||
try {
|
||||
// 部件与方块实体分别选择定位器并打开界面
|
||||
if (host instanceof AEBasePart part) {
|
||||
host.openMenu(player, MenuLocators.forPart(part));
|
||||
highlightWithMessage(pbe.getBlockPos(), part.getSide(), Objects.requireNonNull(pbe.getLevel()).dimension(), 1.0, player);
|
||||
} else {
|
||||
host.openMenu(player, MenuLocators.forBlockEntity(pbe));
|
||||
highlightWithMessage(pbe.getBlockPos(), null, Objects.requireNonNull(pbe.getLevel()).dimension(), 1.0, player);
|
||||
}
|
||||
|
||||
// 先在该 provider 中定位 pattern 的槽位索引,以便计算页码(尽量早退出,按槽位逐个解码)
|
||||
int foundSlot = PatternProviderDataUtil.findSlotForPattern(ppl, pattern.getDefinition());
|
||||
if (foundSlot >= 0) {
|
||||
int pageId = foundSlot / 36;
|
||||
if (pageId > 0) {
|
||||
// 发送 S2C 包通知客户端切换到指定页(客户端会写入 mixin 字段并重排槽位)
|
||||
ModNetwork.CHANNEL.sendTo(new SetProviderPageS2CPacket(pageId), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
}
|
||||
|
||||
// 最后发送高亮包,保证界面已打开
|
||||
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
|
||||
AEKey key = pattern.getOutputs()[0].what();
|
||||
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
return;
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
} else if (provider instanceof com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine machine) {
|
||||
// 处理 MEPatternBufferPartMachine:打开其界面并高亮位置,尽量反射获取槽位页码
|
||||
try {
|
||||
BlockPos pos = machine.getPos();
|
||||
Level level = machine.getLevel();
|
||||
if (pos == null || level == null) continue;
|
||||
if (!level.isClientSide) { // 确保在服务器端执行
|
||||
MachineUIFactory.INSTANCE.openUI(MetaMachine.getMachine(level, pos), player);
|
||||
}
|
||||
|
||||
// 最后发送高亮包,保证界面已打开
|
||||
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
|
||||
AEKey key = pattern.getOutputs()[0].what();
|
||||
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
highlightWithMessage(pos, null, level.dimension(), 1.0, player);
|
||||
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
} else if (provider instanceof org.gtlcore.gtlcore.common.machine.multiblock.part.ae.MEPatternBufferPartMachine machine) {
|
||||
// 处理 MEPatternBufferPartMachine:打开其界面并高亮位置,尽量反射获取槽位页码
|
||||
try {
|
||||
BlockPos pos = machine.getPos();
|
||||
Level level = machine.getLevel();
|
||||
if (pos == null || level == null) continue;
|
||||
if (!level.isClientSide) { // 确保在服务器端执行
|
||||
MachineUIFactory.INSTANCE.openUI(MetaMachine.getMachine(level, pos), player);
|
||||
}
|
||||
|
||||
// 最后发送高亮包,保证界面已打开
|
||||
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
|
||||
AEKey key = pattern.getOutputs()[0].what();
|
||||
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
highlightWithMessage(pos, null, level.dimension(), 1.0, player);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
context.setPacketHandled(true);
|
||||
}
|
||||
|
||||
private static void highlightWithMessage(BlockPos pos, Direction face, ResourceKey<Level> dim, double multiplier, Player player) {
|
||||
if (pos == null || dim == null) {
|
||||
return;
|
||||
}
|
||||
long endTime = System.currentTimeMillis() + (long) (6000 * GlodUtil.clamp(multiplier, 1, 30));
|
||||
if (face == null) {
|
||||
highlight(pos, dim, endTime);
|
||||
} else {
|
||||
var origin = new AABB(2 / 16D, 2 / 16D, 0, 14 / 16D, 14 / 16D, 2 / 16D).move(pos);
|
||||
var center = new AABB(pos).getCenter();
|
||||
switch (face) {
|
||||
case WEST -> origin = FCClientUtil.rotor(origin, center, Direction.Axis.Y, (float) (Math.PI / 2));
|
||||
case SOUTH -> origin = FCClientUtil.rotor(origin, center, Direction.Axis.Y, (float) Math.PI);
|
||||
case EAST -> origin = FCClientUtil.rotor(origin, center, Direction.Axis.Y, (float) (-Math.PI / 2));
|
||||
case UP -> origin = FCClientUtil.rotor(origin, center, Direction.Axis.X, (float) (-Math.PI / 2));
|
||||
case DOWN -> origin = FCClientUtil.rotor(origin, center, Direction.Axis.X, (float) (Math.PI / 2));
|
||||
}
|
||||
highlight(pos, face, dim, endTime, origin);
|
||||
}
|
||||
|
||||
if (player != null) {
|
||||
player.displayClientMessage(Component.translatable("chat.ex_pattern_access_terminal.pos", pos.toShortString(), dim.location().getPath()), false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,11 +14,18 @@ import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
|
|||
import com.extendedae_plus.network.SetBlockHighlightS2CPacket;
|
||||
import com.extendedae_plus.network.SetPatternHighlightS2CPacket;
|
||||
import com.extendedae_plus.network.provider.SetProviderPageS2CPacket;
|
||||
import com.extendedae_plus.util.CompareModVersionUtil;
|
||||
import com.extendedae_plus.util.PatternProviderDataUtil;
|
||||
import com.glodblock.github.extendedae.client.render.EAEHighlightHandler;
|
||||
import com.glodblock.github.extendedae.util.MessageUtil;
|
||||
import com.glodblock.github.glodium.util.GlodUtil;
|
||||
import com.gregtechceu.gtceu.api.gui.factory.MachineUIFactory;
|
||||
import com.gregtechceu.gtceu.api.machine.MetaMachine;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
|
|
@ -70,11 +77,22 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
// 遍历所有样板,找到第一个可用 Provider 并打开 UI
|
||||
for (var pattern : patterns) {
|
||||
var provider = PatternLocator.findValidProvider(craftingService, pattern, grid);
|
||||
if (provider == null) continue;
|
||||
if (provider == null) {
|
||||
for (var pd : craftingService.getProviders(pattern)) {
|
||||
if (pd instanceof com.gregtechceu.gtceu.integration.ae2.machine.MEPatternBufferPartMachine machine) {
|
||||
gtmOpenUI(machine, player, pattern);
|
||||
return;
|
||||
} else if (pd instanceof org.gtlcore.gtlcore.common.machine.multiblock.part.ae.MEPatternBufferPartMachine machine) {
|
||||
gtmOpenUI(machine, player, pattern);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
ProviderUIHelper.openProviderUI(provider, pattern, player);
|
||||
} catch (Exception ignored) {}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
});
|
||||
context.setPacketHandled(true);
|
||||
|
|
@ -82,21 +100,73 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
|
||||
// ===================== 内部工具类 =====================
|
||||
|
||||
/**
|
||||
* 兼容gtm
|
||||
* @param machine 样板总成
|
||||
* @param player 玩家
|
||||
* @param pattern 样板
|
||||
*/
|
||||
private static void gtmOpenUI(MetaMachine machine, ServerPlayer player, IPatternDetails pattern) {
|
||||
try {
|
||||
BlockPos pos = machine.getPos();
|
||||
Level level = machine.getLevel();
|
||||
if (pos == null || level == null) return;
|
||||
if (!level.isClientSide) { // 确保在服务器端执行
|
||||
MachineUIFactory.INSTANCE.openUI(MetaMachine.getMachine(level, pos), player);
|
||||
}
|
||||
|
||||
// 聊天提示
|
||||
if (CompareModVersionUtil.compareTo("expatternprovider", "1.4.7")) {
|
||||
player.displayClientMessage(
|
||||
MessageUtil.createEnhancedHighlightMessage(
|
||||
player,
|
||||
pos,
|
||||
level.dimension(),
|
||||
"chat.ex_pattern_access_terminal.pos"),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
player.displayClientMessage(
|
||||
Component.translatable(
|
||||
"chat.ex_pattern_access_terminal.pos",
|
||||
pos.toShortString(),
|
||||
level.dimension()
|
||||
.location()
|
||||
.getPath()
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
// 最后发送高亮包,保证界面已打开
|
||||
if (pattern.getOutputs() != null && pattern.getOutputs().length > 0 && pattern.getOutputs()[0] != null) {
|
||||
AEKey key = pattern.getOutputs()[0].what();
|
||||
ModNetwork.CHANNEL.sendTo(new SetPatternHighlightS2CPacket(key, true), player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
|
||||
}
|
||||
|
||||
EAEHighlightHandler.highlight(pos, level.dimension(), System.currentTimeMillis() + 15000);
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* GridHelper: 从菜单中获取网格实例
|
||||
*/
|
||||
public static final class GridHelper {
|
||||
private GridHelper() {}
|
||||
private GridHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取菜单对应的 Grid
|
||||
*
|
||||
* @param menu 当前 AEBaseMenu
|
||||
* @return Grid 或 null
|
||||
*/
|
||||
public static IGrid getGridFromMenu(appeng.menu.AEBaseMenu menu) {
|
||||
Object target = menu.getTarget();
|
||||
if (target instanceof IActionHost host && host.getActionableNode() != null) {
|
||||
return host.getActionableNode().getGrid();
|
||||
return host.getActionableNode()
|
||||
.getGrid();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
@ -106,13 +176,15 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
* PatternLocator: 根据样板定位可用的 Provider
|
||||
*/
|
||||
public static final class PatternLocator {
|
||||
private PatternLocator() {}
|
||||
private PatternLocator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找提供指定样板的可用 Provider
|
||||
* @param cs CraftingService
|
||||
*
|
||||
* @param cs CraftingService
|
||||
* @param pattern 样板
|
||||
* @param grid 当前 Grid
|
||||
* @param grid 当前 Grid
|
||||
* @return 第一个可用的 PatternProviderLogic 或 null
|
||||
*/
|
||||
public static PatternProviderLogic findValidProvider(CraftingService cs, IPatternDetails pattern, IGrid grid) {
|
||||
|
|
@ -133,7 +205,8 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
* ProviderUIHelper: 打开 Provider UI 并发送客户端反馈
|
||||
*/
|
||||
public static final class ProviderUIHelper {
|
||||
private ProviderUIHelper() {}
|
||||
private ProviderUIHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开 Provider UI
|
||||
|
|
@ -143,8 +216,8 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
* 4. 发送 Pattern 输出高亮包
|
||||
*
|
||||
* @param provider PatternProviderLogic 实例
|
||||
* @param pattern 样板
|
||||
* @param player 玩家
|
||||
* @param pattern 样板
|
||||
* @param player 玩家
|
||||
*/
|
||||
public static void openProviderUI(PatternProviderLogic provider, IPatternDetails pattern, ServerPlayer player) {
|
||||
var host = ((PatternProviderLogicAccessor) provider).eap$host();
|
||||
|
|
@ -160,7 +233,9 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
new SetBlockHighlightS2CPacket(
|
||||
pbe.getBlockPos(),
|
||||
isPart ? ((AEBasePart) host).getSide() : null,
|
||||
pbe.getLevel().dimension().location(),
|
||||
pbe.getLevel()
|
||||
.dimension()
|
||||
.location(),
|
||||
(long) (6000 * GlodUtil.clamp(1.0, 1, 30))
|
||||
),
|
||||
player.connection.connection,
|
||||
|
|
@ -168,15 +243,30 @@ public class CraftingMonitorOpenProviderC2SPacket {
|
|||
);
|
||||
|
||||
// 聊天提示
|
||||
player.displayClientMessage(
|
||||
Component.translatable(
|
||||
"chat.ex_pattern_access_terminal.pos",
|
||||
pbe.getBlockPos().toShortString(),
|
||||
pbe.getLevel().dimension().location().getPath()
|
||||
),
|
||||
false
|
||||
);
|
||||
|
||||
if (CompareModVersionUtil.compareTo("expatternprovider", "1.4.7")) {
|
||||
player.displayClientMessage(
|
||||
MessageUtil.createEnhancedHighlightMessage(
|
||||
player,
|
||||
pbe.getBlockPos(),
|
||||
pbe.getLevel()
|
||||
.dimension(),
|
||||
"chat.ex_pattern_access_terminal.pos"),
|
||||
false
|
||||
);
|
||||
} else {
|
||||
player.displayClientMessage(
|
||||
Component.translatable(
|
||||
"chat.ex_pattern_access_terminal.pos",
|
||||
pbe.getBlockPos()
|
||||
.toShortString(),
|
||||
pbe.getLevel()
|
||||
.dimension()
|
||||
.location()
|
||||
.getPath()
|
||||
),
|
||||
false
|
||||
);
|
||||
}
|
||||
// 页码同步
|
||||
int slot = PatternProviderDataUtil.findSlotForPattern(provider, pattern.getDefinition());
|
||||
if (slot >= 0) {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,35 @@
|
|||
package com.extendedae_plus.util;
|
||||
|
||||
import net.minecraftforge.fml.ModList;
|
||||
import net.minecraftforge.fml.loading.LoadingModList;
|
||||
import org.apache.maven.artifact.versioning.ComparableVersion;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
//此类代码借鉴于gtlcore
|
||||
public class CompareModVersionUtil {
|
||||
private static final ModList modList = ModList.get();
|
||||
private static final LoadingModList loadingModList = LoadingModList.get();
|
||||
|
||||
public static boolean compareTo(String modId, String version) {
|
||||
Optional<String> versionStr;
|
||||
if (modList == null) {
|
||||
versionStr = loadingModList
|
||||
.getMods()
|
||||
.stream()
|
||||
.filter(mi -> mi.getModId()
|
||||
.equals(modId))
|
||||
.findFirst()
|
||||
.map(mi -> mi.getVersion()
|
||||
.toString());
|
||||
} else {
|
||||
versionStr = modList.getModContainerById(modId)
|
||||
.map(mc -> mc.getModInfo()
|
||||
.getVersion()
|
||||
.toString());
|
||||
}
|
||||
return versionStr
|
||||
.map(v -> new ComparableVersion(v).compareTo(new ComparableVersion(version)) >= 0)
|
||||
.orElse(false);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user