From d95b8ff0499368e85e575a7aa6d3cea7e4ae5efc Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Wed, 10 Sep 2025 13:12:34 +0800 Subject: [PATCH 01/44] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=B3=A8=E5=86=8C?= =?UTF-8?q?=E7=B1=BB=EF=BC=8C=E6=98=8E=E7=A1=AE=E7=B1=BB=E5=88=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 62 +++++++++++++------ .../client/ClientModelEvents.java | 2 +- .../extendedae_plus/client/ClientProxy.java | 25 +++----- 3 files changed, 55 insertions(+), 34 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index bdb0611..a7fa4fd 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -1,28 +1,24 @@ package com.extendedae_plus; import appeng.menu.locator.MenuLocators; +import com.extendedae_plus.client.ClientProxy; import com.extendedae_plus.config.ModConfigs; -import com.extendedae_plus.init.ModBlockEntities; -import com.extendedae_plus.init.ModBlocks; -import com.extendedae_plus.init.ModCreativeTabs; -import com.extendedae_plus.init.ModItems; -import com.extendedae_plus.init.ModMenuTypes; +import com.extendedae_plus.init.*; import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.network.ModNetwork; -import net.minecraftforge.client.ConfigScreenHandler; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.config.ModConfig; +import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; -import net.minecraft.resources.ResourceLocation; - -import com.extendedae_plus.client.ClientProxy; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; /** * ExtendedAE Plus 主mod类 @@ -36,20 +32,23 @@ public class ExtendedAEPlus { public ExtendedAEPlus() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); - + // 在客户端尽早注册内置模型,保证首次资源加载前映射已建立(仿照 AE2 的 AppEngClient 构造期注册) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientProxy::init); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientProxy::initBuiltInModels); // 注册mod初始化事件 modEventBus.addListener(this::commonSetup); - + // 注册方块与方块实体 ModBlocks.BLOCKS.register(modEventBus); ModBlockEntities.BLOCK_ENTITY_TYPES.register(modEventBus); ModItems.ITEMS.register(modEventBus); + + // 在注册阶段将创造模式标签页放入注册表 ModCreativeTabs.TABS.register(modEventBus); + ModMenuTypes.MENUS.register(modEventBus); - + // 注册到Forge事件总线 MinecraftForge.EVENT_BUS.register(this); @@ -57,9 +56,9 @@ public class ExtendedAEPlus { ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); // 客户端侧延迟注册:在 FMLClientSetupEvent 阶段执行(包含 MenuScreens 绑定等) - modEventBus.addListener((FMLClientSetupEvent e) -> ClientProxy.onClientSetup(e)); + // 由下面的 ClientModEvents 负责在客户端总线上接收事件并委派 } - + /** * 通用初始化设置 */ @@ -78,4 +77,31 @@ public class ExtendedAEPlus { public static ResourceLocation id(String path) { return new ResourceLocation(MODID, path); } + + /** + * 客户端专用事件订阅类。 + * 完成客户端相关的延迟注册操作(如菜单界面绑定、渲染器注册、模型加载等),确保这些操作只在客户端执行,避免服务端崩溃。 + */ + @Mod.EventBusSubscriber( + modid = ExtendedAEPlus.MODID, + bus = Mod.EventBusSubscriber.Bus.MOD, + value = Dist.CLIENT + ) + public static class ClientModEvents { + @SubscribeEvent + public static void onClientSetup(final FMLClientSetupEvent event) { + // 直接在此处执行客户端一次性注册(UI/屏幕/渲染器绑定) + // 注册客户端配置界面 + ClientProxy.registerConfigScreen(); + // 菜单 -> 屏幕 绑定 + ClientProxy.registerMenuScreens(); + } + + @SubscribeEvent + public static void onRegisterGeometryLoaders(final ModelEvent.RegisterGeometryLoaders evt) { + try { + ClientProxy.initBuiltInModels(); + } catch (Exception ignored) {} + } + } } diff --git a/src/main/java/com/extendedae_plus/client/ClientModelEvents.java b/src/main/java/com/extendedae_plus/client/ClientModelEvents.java index c867034..fa441d1 100644 --- a/src/main/java/com/extendedae_plus/client/ClientModelEvents.java +++ b/src/main/java/com/extendedae_plus/client/ClientModelEvents.java @@ -22,6 +22,6 @@ public final class ClientModelEvents { event.register(ExtendedAEPlus.id("block/crafting/64x_accelerator_formed_v2")); event.register(ExtendedAEPlus.id("block/crafting/256x_accelerator_formed_v2")); event.register(ExtendedAEPlus.id("block/crafting/1024x_accelerator_formed_v2")); - ClientProxy.init(); + ClientProxy.initBuiltInModels(); } } diff --git a/src/main/java/com/extendedae_plus/client/ClientProxy.java b/src/main/java/com/extendedae_plus/client/ClientProxy.java index 55f9e5f..8b7fb46 100644 --- a/src/main/java/com/extendedae_plus/client/ClientProxy.java +++ b/src/main/java/com/extendedae_plus/client/ClientProxy.java @@ -4,13 +4,12 @@ import appeng.client.render.crafting.CraftingCubeModel; import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.client.render.crafting.EPlusCraftingCubeModelProvider; import com.extendedae_plus.client.screen.GlobalProviderModesScreen; -import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.content.crafting.EPlusCraftingUnitType; import com.extendedae_plus.hooks.BuiltInModelHooks; +import com.extendedae_plus.init.ModMenuTypes; +import net.minecraft.client.gui.screens.MenuScreens; import net.minecraftforge.client.ConfigScreenHandler; import net.minecraftforge.fml.ModLoadingContext; -import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; -import net.minecraft.client.gui.screens.MenuScreens; /** * 客户端模型注册,将 formed 模型注册为内置模型。 @@ -20,7 +19,10 @@ public final class ClientProxy { private static boolean REGISTERED = false; - public static void init() { + /** + * 注册内置模型(formed 模型等)。可被 ModelEvent 或启动阶段直接调用。 + */ + public static void initBuiltInModels() { if (REGISTERED) return; REGISTERED = true; // 注册四种形成态模型为内置模型 @@ -46,17 +48,10 @@ public final class ClientProxy { } /** - * 客户端设置阶段:延迟执行需要访问注册对象的客户端注册。 + * 将菜单类型与对应的屏幕绑定。 */ - public static void onClientSetup(final FMLClientSetupEvent event) { - event.enqueueWork(() -> { - // 确保在首次资源加载前完成内置模型注册(REGISTERED 保护避免重复) - init(); - // 仅在客户端设置阶段执行与 UI 相关的一次性绑定 - registerConfigScreen(); - // 菜单 -> 屏幕 绑定 - MenuScreens.register(ModMenuTypes.NETWORK_PATTERN_CONTROLLER.get(), GlobalProviderModesScreen::new); - }); + public static void registerMenuScreens() { + MenuScreens.register(ModMenuTypes.NETWORK_PATTERN_CONTROLLER.get(), GlobalProviderModesScreen::new); } /** @@ -68,7 +63,7 @@ public final class ClientProxy { ModLoadingContext.get().registerExtensionPoint( ConfigScreenHandler.ConfigScreenFactory.class, () -> new ConfigScreenHandler.ConfigScreenFactory( - (mc, parent) -> new com.extendedae_plus.client.ModConfigScreen(parent)) + (mc, parent) -> new ModConfigScreen(parent)) ); } } From 0b50dfc66c5769e4255233941b3bb2c90c4fc9b9 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 11 Sep 2025 12:07:39 +0800 Subject: [PATCH 02/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 12 + .../ae/parts/EntitySpeedTickerPart.java | 251 ++++++++++++++++++ .../extendedae_plus/config/ModConfigs.java | 8 + .../extendedae_plus/init/ModCreativeTabs.java | 1 + .../com/extendedae_plus/init/ModItems.java | 20 ++ .../extendedae_plus/init/ModMenuTypes.java | 14 +- .../extendedae_plus/init/UpgradeCards.java | 15 ++ .../items/EntitySpeedTickerPartItem.java | 11 + .../menu/EntitySpeedTickerMenu.java | 68 +++++ .../screen/EntitySpeedTickerScreen.java | 39 +++ .../com/extendedae_plus/util/PowerUtils.java | 130 +++++++++ .../ae2/screens/entity_speed_ticker.json | 63 +++++ .../ae2/textures/guis/blank_background.png | Bin 0 -> 1776 bytes .../assets/extendedae_plus/lang/en_us.json | 6 + .../assets/extendedae_plus/lang/zh_cn.json | 5 + .../models/item/entity_speed_ticker.json | 6 + .../models/part/entity_speed_ticker_part.json | 6 + .../textures/part/entity_speed_ticker.png | Bin 0 -> 4259 bytes 18 files changed, 653 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java create mode 100644 src/main/java/com/extendedae_plus/init/UpgradeCards.java create mode 100644 src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java create mode 100644 src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java create mode 100644 src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java create mode 100644 src/main/java/com/extendedae_plus/util/PowerUtils.java create mode 100644 src/main/resources/assets/ae2/screens/entity_speed_ticker.json create mode 100644 src/main/resources/assets/ae2/textures/guis/blank_background.png create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json create mode 100644 src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json create mode 100644 src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker.png diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index a7fa4fd..416740e 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -1,11 +1,14 @@ package com.extendedae_plus; +import appeng.init.client.InitScreens; import appeng.menu.locator.MenuLocators; import com.extendedae_plus.client.ClientProxy; import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.*; +import com.extendedae_plus.menu.EntitySpeedTickerMenu; import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.network.ModNetwork; +import com.extendedae_plus.screen.EntitySpeedTickerScreen; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; @@ -65,6 +68,8 @@ public class ExtendedAEPlus { private void commonSetup(final FMLCommonSetupEvent event) { // 注册本模组网络通道与数据包 event.enqueueWork(() -> { + // 注册升级卡 + new UpgradeCards(event); ModNetwork.register(); // 注册自定义 Curios 宿主定位器,便于将菜单宿主信息在服务端与客户端间同步 MenuLocators.register(CuriosItemLocator.class, CuriosItemLocator::writeToPacket, CuriosItemLocator::readFromPacket); @@ -93,6 +98,11 @@ public class ExtendedAEPlus { // 直接在此处执行客户端一次性注册(UI/屏幕/渲染器绑定) // 注册客户端配置界面 ClientProxy.registerConfigScreen(); + + InitScreens.register(ModMenuTypes.ENTITY_TICKER_MENU.get(), + EntitySpeedTickerScreen::new, + "/screens/entity_speed_ticker.json"); + // 菜单 -> 屏幕 绑定 ClientProxy.registerMenuScreens(); } @@ -101,6 +111,8 @@ public class ExtendedAEPlus { public static void onRegisterGeometryLoaders(final ModelEvent.RegisterGeometryLoaders evt) { try { ClientProxy.initBuiltInModels(); + // 注册 AE2 部件模型(例如 entity_ticker_part_item),仿照 CrazyAddons 的做法 + ModItems.registerPartModels(); } catch (Exception ignored) {} } } diff --git a/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java b/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java new file mode 100644 index 0000000..75a4bf8 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java @@ -0,0 +1,251 @@ +package com.extendedae_plus.ae.parts; + +import appeng.api.config.Actionable; +import appeng.api.config.PowerMultiplier; +import appeng.api.networking.GridFlags; +import appeng.api.networking.IGridNode; +import appeng.api.networking.ticking.IGridTickable; +import appeng.api.networking.ticking.TickRateModulation; +import appeng.api.networking.ticking.TickingRequest; +import appeng.api.parts.IPartCollisionHelper; +import appeng.api.parts.IPartItem; +import appeng.api.parts.IPartModel; +import appeng.api.upgrades.IUpgradeableObject; +import appeng.core.definitions.AEItems; +import appeng.items.parts.PartModels; +import appeng.menu.MenuOpener; +import appeng.menu.locator.MenuLocators; +import appeng.parts.automation.UpgradeablePart; +import appeng.parts.p2p.P2PModels; +import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.init.ModMenuTypes; +import com.extendedae_plus.menu.EntitySpeedTickerMenu; +import com.extendedae_plus.util.PowerUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.MenuProvider; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +/** + * EntitySpeedTickerPart 是一个可升级的 AE2 部件

+ * 该部件可以加速目标方块实体的 tick 速率,消耗 AE 网络能量,并支持加速卡升级

+ * 功能受Crazy AE2 Addons启发 + */ +public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTickable, MenuProvider, IUpgradeableObject { + // 当前打开的菜单实例(如果有) + public EntitySpeedTickerMenu menu; + + // P2P 模型,用于渲染部件的外观 + private static final P2PModels MODELS = new P2PModels( + new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_part")); + + /** + * 获取该部件的所有模型(用于渲染) + * @return 模型列表 + */ + @PartModels + public static List getModels() { + return MODELS.getModels(); + } + + /** + * 构造函数,初始化部件并设置网络节点属性 + * @param partItem 部件物品 + */ + public EntitySpeedTickerPart(IPartItem partItem) { + super(partItem); + // 设置网络节点属性:需要通道、空闲功耗为1,并注册为 IGridTickable 服务 + this.getMainNode() + .setFlags(GridFlags.REQUIRE_CHANNEL) + .setIdlePowerUsage(1) + .addService(IGridTickable.class, this); + } + + /** + * 获取当前状态下的静态模型(用于渲染) + * @return 当前状态的模型 + */ + public IPartModel getStaticModels() { + return MODELS.getModel(this.isPowered(), this.isActive()); + } + + /** + * 当玩家激活部件(右键)时调用,打开自定义菜单 + * @param player 玩家 + * @param hand 手 + * @param pos 点击位置 + * @return 总是返回 true,表示激活成功 + */ + @Override + public boolean onPartActivate(Player player, InteractionHand hand, Vec3 pos) { + // 仅在服务端打开菜单 + if (!player.getCommandSenderWorld().isClientSide()) { + MenuOpener.open(ModMenuTypes.ENTITY_TICKER_MENU.get(), player, MenuLocators.forPart(this)); + } + return true; + } + + /** + * 定义部件的碰撞箱(用于物理碰撞和渲染) + * @param bch 碰撞辅助器 + */ + @Override + public void getBoxes(IPartCollisionHelper bch) { + bch.addBox(5, 5, 12, 11, 11, 13); + bch.addBox(3, 3, 13, 13, 13, 14); + bch.addBox(2, 2, 14, 14, 14, 16); + } + + /** + * 获取定时请求,决定本部件多久 tick 一次 + * @param iGridNode 网络节点 + * @return TickingRequest 对象 + */ + @Override + public TickingRequest getTickingRequest(IGridNode iGridNode) { + // 每 1 tick 执行一次 + return new TickingRequest(1, 1, false, true); + } + + /** + * 当升级卡数量发生变化时调用,通知菜单更新 + */ + @Override + public void upgradesChanged() { + if (this.menu != null) { + // 使用 AE2 风格:当升级发生变化时让菜单广播变化(槽/数据会被同步),客户端会基于槽内容重新计算并刷新界面 + this.menu.broadcastChanges(); + } + } + + /** + * 网络定时回调,每次 tick 时调用 + * @param iGridNode 网络节点 + * @param ticksSinceLastCall 距离上次调用经过的 tick 数 + * @return TickRateModulation.IDLE 表示继续保持当前 tick 速率 + */ + @Override + public TickRateModulation tickingRequest(IGridNode iGridNode, int ticksSinceLastCall) { + // 获取目标方块实体(本部件朝向的方块) + BlockEntity target = getLevel().getBlockEntity(getBlockEntity().getBlockPos().relative(getSide())); + // 仅在目标存在且部件处于激活状态时执行加速 + if (target != null && isActive()) { + ticker(target); + } + return TickRateModulation.IDLE; + } + + /** + * 以指定速度对目标方块实体进行 tick 操作 + * @param blockEntity 需要被 tick 的方块实体 + * @param 方块实体类型 + */ + private void ticker(@NotNull T blockEntity) { + if (this.getGridNode() == null + || this.getMainNode() == null + || this.getMainNode().getGrid() == null) { + return; + } + +// String id = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString(); + + // 获取方块实体的位置 + BlockPos pos = blockEntity.getBlockPos(); + if (blockEntity.getLevel() == null) return; + + // 获取该方块实体的 Ticker + @SuppressWarnings("unchecked") + BlockEntityTicker blockEntityTicker = this.getLevel() + .getBlockState(pos) + .getTicker(this.getLevel(), (BlockEntityType) blockEntity.getType()); + if (blockEntityTicker == null) return; + + int speedCardCount = getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD); + int energyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD); + + // 计算本次 tick 所需能量 + // - 基础消耗为 512 + // - 加速卡的数量对能耗有分段增长: + // 0: 无增长 + // 1: 翻倍 + // 2-6: 指数增长(较快) + // 7-8: 幂级数增长(极高) + // 使用工具类统一计算增长因子与原始功耗,并从网络中抽取对应能量 + double requiredPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); + + // 先模拟提取以检查网络中是否有足够能量,再真正抽取 + double simulated = getMainNode().getGrid().getEnergyService() + .extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG); + if (simulated < requiredPower) return; + + double extractedPower = getMainNode().getGrid().getEnergyService() + .extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG); + if (extractedPower < requiredPower) return; + + // 计算加速倍数:基于 2 的次方,并把 8 张映射到最大 1024x(2^10) + int speed = PowerUtils.getSpeedMultiplier(speedCardCount); + + // 执行 tick 操作 + for (int i = 0; i < speed - 1; i++) { + blockEntityTicker.tick( + blockEntity.getLevel(), + blockEntity.getBlockPos(), + blockEntity.getBlockState(), + blockEntity + ); + } + } + + /** + * 判断部件是否有自定义名称 + * @return 是否有自定义名称 + */ + @Override + public boolean hasCustomName() { + return super.hasCustomName(); + } + + /** + * 获取部件的显示名称 + * @return 显示名称 + */ + @Override + public @NotNull Component getDisplayName() { + return super.getDisplayName(); + } + + /** + * 创建自定义菜单(GUI) + * @param containerId 容器ID + * @param playerInventory 玩家背包 + * @param player 玩家 + * @return 菜单实例 + */ + @Override + public @Nullable AbstractContainerMenu createMenu(int containerId, + @NotNull Inventory playerInventory, + @NotNull Player player) { + return new EntitySpeedTickerMenu(containerId, playerInventory, this); + } + + /** + * 获取可用的升级卡槽数量 + * @return 升级卡槽数量 + */ + @Override + protected int getUpgradeSlots() { + return 8; + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/config/ModConfigs.java b/src/main/java/com/extendedae_plus/config/ModConfigs.java index 5f8e545..a746b53 100644 --- a/src/main/java/com/extendedae_plus/config/ModConfigs.java +++ b/src/main/java/com/extendedae_plus/config/ModConfigs.java @@ -12,6 +12,8 @@ public final class ModConfigs { public static final ForgeConfigSpec.BooleanValue PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT; public static final ForgeConfigSpec.IntValue SMART_SCALING_MAX_MULTIPLIER; public static final ForgeConfigSpec.IntValue SMART_SCALING_MIN_BENEFIT_FACTOR; + public static final ForgeConfigSpec.IntValue EntityTickerCost; + static { ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); @@ -77,6 +79,12 @@ public final class ModConfigs { "影响进入界面时SlotsRow的默认可见性,仅影响客户端显示" ) .define("patternTerminalShowSlotsDefault", true); + + + EntityTickerCost = builder + .comment("实体加速器的能量消耗基础值") + .defineInRange("EntityTickerCost", 512, 0, Integer.MAX_VALUE); + builder.pop(); COMMON_SPEC = builder.build(); } diff --git a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java index e48a376..d44b721 100644 --- a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java +++ b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java @@ -26,6 +26,7 @@ public final class ModCreativeTabs { output.accept(ModItems.ACCELERATOR_64x.get()); output.accept(ModItems.ACCELERATOR_256x.get()); output.accept(ModItems.ACCELERATOR_1024x.get()); + output.accept(ModItems.ENTITY_TICKER_PART_ITEM.get()); }) .build()); } diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index d2d290f..d3ddcb2 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -1,6 +1,10 @@ package com.extendedae_plus.init; +import appeng.api.parts.IPart; +import appeng.api.parts.PartModels; +import appeng.items.parts.PartModelsHelper; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.items.EntitySpeedTickerPartItem; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraftforge.registries.DeferredRegister; @@ -47,4 +51,20 @@ public final class ModItems { "1024x_crafting_accelerator", () -> new BlockItem(ModBlocks.ACCELERATOR_1024x.get(), new Item.Properties()) ); + + public static final RegistryObject ENTITY_TICKER_PART_ITEM = + ITEMS.register("entity_speed_ticker", + () -> new EntitySpeedTickerPartItem(new Item.Properties())); + + /** + * 为 PartItem 注册 AE2 部件模型。 + * 在客户端进行模型/几何体注册时调用。 + */ + public static void registerPartModels() { + PartModels.registerModels( + PartModelsHelper.createModels( + ENTITY_TICKER_PART_ITEM.get().getPartClass().asSubclass(IPart.class) + ) + ); + } } diff --git a/src/main/java/com/extendedae_plus/init/ModMenuTypes.java b/src/main/java/com/extendedae_plus/init/ModMenuTypes.java index 47a0936..238ad40 100644 --- a/src/main/java/com/extendedae_plus/init/ModMenuTypes.java +++ b/src/main/java/com/extendedae_plus/init/ModMenuTypes.java @@ -1,6 +1,9 @@ package com.extendedae_plus.init; +import appeng.menu.implementations.MenuTypeBuilder; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; +import com.extendedae_plus.menu.EntitySpeedTickerMenu; import com.extendedae_plus.menu.NetworkPatternControllerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraftforge.common.extensions.IForgeMenuType; @@ -9,12 +12,19 @@ import net.minecraftforge.registries.ForgeRegistries; import net.minecraftforge.registries.RegistryObject; public final class ModMenuTypes { - private ModMenuTypes() {} - public static final DeferredRegister> MENUS = DeferredRegister.create(ForgeRegistries.MENU_TYPES, ExtendedAEPlus.MODID); + private ModMenuTypes() { + } + public static final RegistryObject> NETWORK_PATTERN_CONTROLLER = MENUS.register("network_pattern_controller", () -> IForgeMenuType.create(NetworkPatternControllerMenu::new)); + + public static final RegistryObject> ENTITY_TICKER_MENU = + MENUS.register("entity_speed_ticker", + () -> MenuTypeBuilder + .create(EntitySpeedTickerMenu::new, EntitySpeedTickerPart.class) + .build("entity_speed_ticker")); } diff --git a/src/main/java/com/extendedae_plus/init/UpgradeCards.java b/src/main/java/com/extendedae_plus/init/UpgradeCards.java new file mode 100644 index 0000000..8c7dd5d --- /dev/null +++ b/src/main/java/com/extendedae_plus/init/UpgradeCards.java @@ -0,0 +1,15 @@ +package com.extendedae_plus.init; + +import appeng.api.upgrades.Upgrades; +import appeng.core.definitions.AEItems; +import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; + + +public class UpgradeCards { + public UpgradeCards(final FMLCommonSetupEvent event) { + event.enqueueWork(() -> { + Upgrades.add(AEItems.SPEED_CARD, ModItems.ENTITY_TICKER_PART_ITEM.get(), 8, "group.entity_ticker.name"); + Upgrades.add(AEItems.ENERGY_CARD, ModItems.ENTITY_TICKER_PART_ITEM.get(), 8, "group.entity_ticker.name"); + }); + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java b/src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java new file mode 100644 index 0000000..011cebf --- /dev/null +++ b/src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java @@ -0,0 +1,11 @@ +package com.extendedae_plus.items; + +import appeng.items.parts.PartItem; +import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; + + +public class EntitySpeedTickerPartItem extends PartItem { + public EntitySpeedTickerPartItem(Properties properties) { + super(properties, EntitySpeedTickerPart.class, EntitySpeedTickerPart::new); + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java new file mode 100644 index 0000000..7b93fb9 --- /dev/null +++ b/src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java @@ -0,0 +1,68 @@ +package com.extendedae_plus.menu; + +import appeng.core.definitions.AEItems; +import appeng.menu.implementations.UpgradeableMenu; +import appeng.menu.slot.OptionalFakeSlot; +import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; +import com.extendedae_plus.init.ModMenuTypes; +import com.extendedae_plus.screen.EntitySpeedTickerScreen; +import net.minecraft.client.Minecraft; +import net.minecraft.world.entity.player.Inventory; + +// 实体加速器菜单,负责与客户端界面同步数据 +public class EntitySpeedTickerMenu extends UpgradeableMenu { + // 已安装的速度卡数量 + public int speedCardCount; + // 已安装的能量卡数量 + public int energyCardCount; + + // 构造方法,初始化菜单并与部件绑定 + public EntitySpeedTickerMenu(int id, Inventory ip, EntitySpeedTickerPart host) { + super(ModMenuTypes.ENTITY_TICKER_MENU.get(), id, ip, host); + // 让部件持有当前菜单实例,便于通信 + getHost().menu = this; + } + + // 当服务器数据同步到客户端时调用 + @Override + public void onServerDataSync() { + super.onServerDataSync(); + // 重新统计速度卡和能量卡数量 + this.speedCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD); + this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD); + // 如果在客户端,刷新界面 + if (isClientSide()) { + if (Minecraft.getInstance().screen instanceof EntitySpeedTickerScreen screen) { + screen.refreshGui(); + } + } + } + + // 当任意槽位发生变化时调用 + @Override + public void onSlotChange(net.minecraft.world.inventory.Slot slot) { + super.onSlotChange(slot); + // 客户端重新统计卡数量并刷新界面 + if (isClientSide()) { + this.speedCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD); + this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD); + if (Minecraft.getInstance().screen instanceof EntitySpeedTickerScreen screen) { + screen.refreshGui(); + } + } + } + + @Override + public void broadcastChanges(){ + // 遍历所有槽位,清理未启用但有物品显示的 OptionalFakeSlot + for (Object o : this.slots) { + if (o instanceof OptionalFakeSlot fs) { + if (!fs.isSlotEnabled() && !fs.getDisplayStack().isEmpty()) { + fs.clearStack(); + } + } + } + // 调用标准的同步方法,通知监听者数据已更新 + this.standardDetectAndSendChanges(); + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java new file mode 100644 index 0000000..8929071 --- /dev/null +++ b/src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java @@ -0,0 +1,39 @@ +package com.extendedae_plus.screen; + +import appeng.client.gui.implementations.UpgradeableScreen; +import appeng.client.gui.style.ScreenStyle; +import com.extendedae_plus.menu.EntitySpeedTickerMenu; +import com.extendedae_plus.util.PowerUtils; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; + +public class EntitySpeedTickerScreen extends UpgradeableScreen { + + public EntitySpeedTickerScreen( + EntitySpeedTickerMenu menu, Inventory playerInventory, Component title, ScreenStyle style) { + super((C) menu, playerInventory, title, style); + } + + @Override + protected void updateBeforeRender(){ + super.updateBeforeRender(); + textData(); + } + + public void refreshGui(){ + textData(); + } + + private void textData() { + int speedCardCount = getMenu().speedCardCount; + int energyCardCount = getMenu().energyCardCount; + + double finalPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); + int speed = PowerUtils.getSpeedMultiplier(speedCardCount); + double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount); + + setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", speed)); + setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", PowerUtils.formatPower(finalPower))); + setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java new file mode 100644 index 0000000..ef42443 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -0,0 +1,130 @@ +package com.extendedae_plus.util; + +import com.extendedae_plus.config.ModConfigs; + +/** + * 用于计算实体加速器的能耗与加速倍率的工具类 + */ +public final class PowerUtils { + private PowerUtils() {} + + /** + * 计算加速卡数量对应的加速倍率(返回 2 的幂次方) + * 0 张卡 = 1x,8 张卡 = 1024x + */ + public static int getSpeedMultiplier(int speedCardCount) { + if (speedCardCount <= 0) return 1; + // 线性映射 0~8 -> 0~10,最大 2^10=1024 + int exponent = (int) Math.round((10.0 / 8.0) * speedCardCount); + exponent = Math.min(exponent, 10); + return (int) Math.pow(2, exponent); + } + + /** + * 计算加速卡数量对应的能耗增长因子 + * 0: 1x,1: 2x,2-6: 2^(2*count),7-8: 2^(3*count) + */ + public static double getGrowthFactor(int speedCardCount) { + if (speedCardCount <= 0) return 1.0; + if (speedCardCount == 1) return 2.0; + if (speedCardCount <= 6) return Math.pow(2.0, 2.0 * speedCardCount); + return Math.pow(2.0, 3.0 * speedCardCount); + } + + /** + * 计算加速卡数量对应的原始能耗(未减免) + * @param speedCardCount 加速卡数量 + * @return 原始能耗 + */ + public static double getRawPower(int speedCardCount) { + double base = ModConfigs.EntityTickerCost.get(); + return base * getGrowthFactor(speedCardCount); + } + + /** + * 计算能源卡数量对应的能耗减免百分比 + * 0: 0%,1: 10%,8: 50%,2-7: 0.5*(1-0.7^n) + */ + public static double getReductionPercent(int energyCardCount) { + if (energyCardCount <= 0) return 0.0; + if (energyCardCount == 1) return 0.1; + if (energyCardCount >= 8) return 0.5; + return 0.5 * (1.0 - Math.pow(0.7, energyCardCount)); + } + + /** + * 计算最终能耗(取整,最小为 1) + * @param speedCardCount 加速卡数量 + * @param energyCardCount 能源卡数量 + * @return 最终能耗(int) + */ + public static int getFinalPowerDraw(int speedCardCount, int energyCardCount) { + double raw = getRawPower(speedCardCount); + double reduction = getReductionPercent(energyCardCount); + // 与原始实现兼容:raw * (1 - reduction) 后按 0.5 的单位转换(与 AE/FE 换算保持一致) + double adjusted = raw * (1.0 - reduction) / 2.0; + return (int) Math.max(1, Math.round(adjusted)); + } + + /** + * 计算最终能耗(浮点数) + * @param speedCardCount 加速卡数量 + * @param energyCardCount 能源卡数量 + * @return 最终能耗(double) + */ + public static double getFinalPower(int speedCardCount, int energyCardCount) { + double raw = getRawPower(speedCardCount); + double reduction = getReductionPercent(energyCardCount); + // 返回与实际抽取值一致的浮点能耗(包含与原实现一致的 /2 单位转换) + return raw * (1.0 - reduction) / 2.0; + } + + /** + * 返回能源卡减免后剩余的功耗比率(例如 1 张能源卡 -> 0.9) + * @param energyCardCount 能源卡数量 + * @return 剩余功耗比率 + */ + public static double getRemainingRatio(int energyCardCount) { + return 1.0 - getReductionPercent(energyCardCount); + } + + /** + * 将能耗数字按单位缩写(K/M/G/T/P/E)格式化为更短的字符串 + * 例如 1500 -> "1.50K", 2000000 -> "2.00M" + */ + public static String formatPower(double value) { + double abs = Math.abs(value); + if (abs >= 1e18) return formatWithSuffix(value, 1e18, "E"); + if (abs >= 1e15) return formatWithSuffix(value, 1e15, "P"); + if (abs >= 1e12) return formatWithSuffix(value, 1e12, "T"); + if (abs >= 1e9) return formatWithSuffix(value, 1e9, "G"); + if (abs >= 1e6) return formatWithSuffix(value, 1e6, "M"); + if (abs >= 1e3) return formatWithSuffix(value, 1e3, "K"); + // 小于 1000 直接返回整数形式 + if (Math.floor(value) == value) { + return String.format("%d", (long) value); + } + return String.format("%.2f", value); + } + + private static String formatWithSuffix(double value, double unit, String suffix) { + double v = value / unit; + // 如果 v 是整数则不显示小数 + if (Math.abs(v - Math.round(v)) < 1e-9) { + return String.format("%d%s", Math.round(v), suffix); + } + return String.format("%.2f%s", v, suffix); + } + + /** + * 将剩余功耗比率格式化为百分比字符串(例如 0.9 -> "90%") + */ + public static String formatPercentage(double ratio) { + double pct = ratio * 100.0; + // 如果为整数则无小数 + if (Math.abs(pct - Math.round(pct)) < 1e-9) { + return String.format("%d%%", Math.round(pct)); + } + return String.format("%.2f%%", pct); + } +} diff --git a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json new file mode 100644 index 0000000..acde6c9 --- /dev/null +++ b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json @@ -0,0 +1,63 @@ +{ + "$schema": "schema.json", + "includes": [ + "common/common.json", + "common/player_inventory.json" + ], + "background": { + "texture": "guis/blank_background.png", + "srcRect": [ + 0, + 0, + 176, + 205 + ] + }, + "text": { + "dialog_title": { + "text": { + "translate": "item.extendedae_plus.entity_speed_ticker" + }, + "position": { + "left": 8, + "top": 6 + } + }, + "speed": { + "position": { + "top": 45, + "left": 88 + }, + "align": "CENTER" + }, + "energy": { + "position": { + "top": 60, + "left": 88 + }, + "align": "CENTER" + }, + "power_ratio": { + "position": { + "top": 75, + "left": 88 + }, + "align": "CENTER" + } + }, + "widgets": { + "toolbox": { + "right": -2, + "bottom": 50, + "width": 68, + "height": 68 + } + }, + "slots": { + "TOOLBOX": { + "bottom": 42, + "right": -10, + "grid": "BREAK_AFTER_3COLS" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/ae2/textures/guis/blank_background.png b/src/main/resources/assets/ae2/textures/guis/blank_background.png new file mode 100644 index 0000000000000000000000000000000000000000..daf4474cd4be274c4c9b5cdc74492b30c075de09 GIT binary patch literal 1776 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$5xr)7d$|)7e>}peR2rGbfdS zL1SX=L|c!;4l+mMgO@5zRVouGJP}}h)74eRTeLf2;TF-TQiGjexM!KDXzKMfWgk4) ze{@xI_vUqc>zWjPFh0_=(A?$G`QMvMH_680-SOSk{kzK>F03-V`lg$CRhs0?6sI%d zVMh;W|KUiKaCA{kd$saS65qVXujTCa-8)(_?fXvq;}e2RBp(QOKK3!!dBpqZrmy$& zJ^nIjqMnL&>hnxqG#%-WnI2pBIHoM(!OTSE=`+>&gu9>0O{<;}$}_d1&0^6Csi)kP z(?!ok&$$}aT>9>0yo64ccI3LtGVVg&9*VqzMp7#lv2hzlnFjf!WY|A^C|~?1v*_fL zRZSC<8B148kg@+E|L5H`9bf;Qo(EYj{7t7Z3 zjNdAIZ(db$cgT?5vEyCVC%J;1%sqB5Cn;J^n!hYSi}8K>7hl$dCt?yY#nrFhJpRIX zA~5{4`GJFq0=mK9b{*f%URC}3yU+6d@>3=iZSk4S9s`UOwj^(N7a$D;Kb?2i11Zh| zkH}&M20djEW~^9hUj`IpFY)wsWq--cFUYIQe=<=RC?r|p8d2h$pPQSSSHj?2l$uzQ znxasiS(2gP?&%v4-pD7;z`%0S)5S5Q;?~={u|cyFL>eA8+pjJXWs>GhkuQ`N5P#TO z=zq>bU*^_DzeOj%3wGF@U;DUo*+boh54UvGw>6v&sNni!H}SB6#lM{s#B&2X9Mr=3 z>h#Wj{=C`vT2DHIJky5TZ*8=7Zl!JR?C4ncdJbob1#`iNW(Ec(1`Y-Vh6XAzsAm$~ zMN~Gjhf$+TNlB?K@k7pripQ_7yuK=l;s2VF&F{Gn8@Sxw=6Se#QO72oCEXI`rAS-o1P_}KgZnZ*Z8 z85}@`01JZvGNVD5+29__=by@JciKJ5>a(L z?`5H(s`{FdkLK)Jm%KMlKk1wSPxq|DTe`m6ul~;6xclzA!{XtquipRtGnjAEy4U+` z)93?xtugEhd%D$)W~CxA18n6PRYETRebJe=j~P?xkq${G3$f3Z*?oH^DdjX=RUj} z{=3lcmDs(Q;-XyEdD-XoJ+I7+?gBD@>N>po&uvgwzs_=-h`)9F{iCi9DDjOFG7a2j z_xk4U>ejz5!@@A*#KGH*%kLc8eSYEXNc~Fg_lm)}4}E7|-j@4m?a`gj3}mAl#SPjY z-{7iQww+chj{x|;FEI8-<54CU4e*OAo zTFPuNr<=Q>l375oFj(a1YGVey4_mo`WfzIyk54^AFuxpE$4yr$kXBDuKbLh*2~7a1 ClaMn2 literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 3de5a8c..93331f1 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -1,4 +1,9 @@ { + "item.extendedae_plus.entity_speed_ticker": "Entity Speed Ticker", + "screen.extendedae_plus.entity_speed_ticker.energy": "Energy Usage: %s FE/t", + "screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power ratio: %s", + "screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d", + "gui.expatternprovider.toggle_slots": "Toggle Slots", "gui.expatternprovider.hide_slots": "Hide Slots", "gui.expatternprovider.show_slots": "Show Slots", @@ -27,6 +32,7 @@ "extendedae_plus.tooltip.locked": "Locked: %s" , "screen.extendedae_plus.title": "ExtendedAE Plus Config", + "config.extendedae_plus.pageMultiplier": "Pattern Provider Page Multiplier", "config.extendedae_plus.pageMultiplier_with_range": "Pattern Provider Page Multiplier (1-64)", "config.extendedae_plus.wirelessMaxRange": "Wireless Max Range", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 4e6ad18..09eadc2 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -29,6 +29,11 @@ "item.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元", "item.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元", + "item.extendedae_plus.entity_speed_ticker": "实体加速器", + "screen.extendedae_plus.entity_speed_ticker.energy": "能耗: %s FE/t", + "screen.extendedae_plus.entity_speed_ticker.power_ratio": "功耗比例: %s", + "screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d", + "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "无线收发器信息", "config.jade.plugin_extendedae_plus.wt_frequency": "显示频率", "config.jade.plugin_extendedae_plus.wt_master_mode": "显示主/从模式", diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json new file mode 100644 index 0000000..62f3cea --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json @@ -0,0 +1,6 @@ +{ + "parent": "ae2:item/p2p_tunnel_base", + "textures": { + "type": "extendedae_plus:part/entity_speed_ticker" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json new file mode 100644 index 0000000..3e091c5 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json @@ -0,0 +1,6 @@ +{ + "parent": "ae2:part/p2p/p2p_tunnel_base", + "textures": { + "type": "extendedae_plus:part/entity_speed_ticker" + } +} \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker.png b/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker.png new file mode 100644 index 0000000000000000000000000000000000000000..488c71509fbc6605dadde40bda3cfa267c38b969 GIT binary patch literal 4259 zcmeHKeQXow89zfws0&jd7f8(H~Gs-W||)|V;DBmTk0-H_YD1-o`!xG42}SF>uId4 z(#k;$k3^NATnllnAp&t2mxCA z`n>Nqk*#>w^9Rlp|Ka4JefZGQ{@ue)&)t#O<14jzLRoODwlJ@p#apdzk zmoLv9E_pq6>hUF+gC;4<_Yt7|_YAD9>Yj7y+^P*Adt^vk-Z=F_M_{J6ZEqQdnKsBp zMSgEl(P%m-i8t1~;wtS~lGVGiqJx-|zW9ad!J5T=9#7Vr&7S@KOXha|^&fvV&G*pO z*$|I;Td-rGT`cY1=d&kgU z=70UviJe62lkb@4Ip_MD%%^TOjdb4#pYA`u`xmocoO*=nypw5~(zWEb;PSN-omY9& z@Y$o=F5LRlj-!8n`1(s*<`zuZ*tu@=z?L7}Ftsi|da}jx;MSZkWpgia^Jm4^UQOSq ztXpS4bZDrcY{A+^bsayQnw2%>!&z|OPY!o|&~@n9v+v!$Z5lily+niGe2LnwUPkRz z<$IDBm5>EUiU2L~Pz3cIhUGsNj{tEM)Nlb-%V8IBqw50#mn9dm!tSGeks??lmo`RW zMPpf|*tkk`O2lIY=KMI1076g$csx`aR{6M#FmQSFtcxiEH%zouE~3ik$BUFG#BCOv zg(f|5xt=8o%y@oO3i9Rd;v@uma}hO~7U3x>7K>S8R*Mp?rWmKwNzp9DvLvz~)rPPJ z;$&FO(IFBTZm5b;Iikr*7}qg@pwwwDf*8=Np3$t4S6RA5~>0Y#1!^H@OIY(Yp00>hD9kYzZ)IRx4&q(FJYss_R$)S(c#MMgMc zFb_DGphN;T=pbzZDl4D`Nai_$g1||vO%QA;5X+)6>Pk?X8kG(uAt;;O4j4OQBWbG> zMFZ_t(&+#+X|ppyjTm^!YiltZvW13I4!XSL_C9LsTxo#yP;aiirhs-j-hQ5o7|br>4GFg!{J zQ491=MF55zWy2RmA<&d)rJ~fj2t6oV_Z(CE&_GE*18$%}1WL0uo?&?_Q%Q5Yjo}&Y zQJUfD6njOIgAM=BS|1-gKT-5jSw-tN7^1{XRlwDWx5R6$Yzz~Q8)Lx(F_D4_>S2Oo zgq2W-WU`dLV~l2-PyG)c`G!Ht z7K8i}GPHG}osb&a3X^=HwZF?xvJT(n5;#7&$b|Tvq-&C{2{AAs(1I%cH_OH16?i2nWMkv%O)a&M$Gpkmm4_v@Dl+wsOc zBuv-5K2Q2*GZv&R%>0mjdJz&W^STQw9lsZ!nfI@?ncKxs=+4f0zLJ;cKQ|!$`uwy- z7w_5J+`Rvhe+~@vWbC>)Ek2XxxN3Agd<{F;gQb@n_cm7xS Date: Thu, 11 Sep 2025 16:47:51 +0800 Subject: [PATCH 03/44] =?UTF-8?q?feat:=20=E4=BF=AE=E5=A4=8D=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8=E6=A8=A1=E5=9E=8B=E5=92=8C?= =?UTF-8?q?=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae/parts/EntitySpeedTickerPart.java | 38 ++++++++++-------- .../models/item/entity_speed_ticker.json | 4 +- .../part/entity_speed_ticker_has_channel.json | 3 ++ .../models/part/entity_speed_ticker_off.json | 3 ++ .../models/part/entity_speed_ticker_on.json | 3 ++ .../models/part/entity_speed_ticker_part.json | 4 +- .../textures/part/entity_speed_ticker.png | Bin 4259 -> 0 bytes .../part/entity_speed_ticker_font.png | Bin 0 -> 3632 bytes 8 files changed, 35 insertions(+), 20 deletions(-) create mode 100644 src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_has_channel.json create mode 100644 src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_off.json create mode 100644 src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_on.json delete mode 100644 src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker.png create mode 100644 src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_font.png diff --git a/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java b/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java index 75a4bf8..87c7ed3 100644 --- a/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java +++ b/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java @@ -15,8 +15,8 @@ import appeng.core.definitions.AEItems; import appeng.items.parts.PartModels; import appeng.menu.MenuOpener; import appeng.menu.locator.MenuLocators; +import appeng.parts.PartModel; import appeng.parts.automation.UpgradeablePart; -import appeng.parts.p2p.P2PModels; import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.menu.EntitySpeedTickerMenu; @@ -36,8 +36,6 @@ import net.minecraft.world.phys.Vec3; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.List; - /** * EntitySpeedTickerPart 是一个可升级的 AE2 部件

* 该部件可以加速目标方块实体的 tick 速率,消耗 AE 网络能量,并支持加速卡升级

@@ -47,19 +45,22 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka // 当前打开的菜单实例(如果有) public EntitySpeedTickerMenu menu; - // P2P 模型,用于渲染部件的外观 - private static final P2PModels MODELS = new P2PModels( - new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_part")); + public static final ResourceLocation MODEL_BASE = new ResourceLocation( + ExtendedAEPlus.MODID, "part/entity_speed_ticker_part"); - /** - * 获取该部件的所有模型(用于渲染) - * @return 模型列表 - */ @PartModels - public static List getModels() { - return MODELS.getModels(); + public static final PartModel MODELS_OFF; + @PartModels + public static final PartModel MODELS_ON; + @PartModels + public static final PartModel MODELS_HAS_CHANNEL; + + static { + MODELS_OFF = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_off")); + MODELS_ON = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_on")); + MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_has_channel")); } - + /** * 构造函数,初始化部件并设置网络节点属性 * @param partItem 部件物品 @@ -78,7 +79,13 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka * @return 当前状态的模型 */ public IPartModel getStaticModels() { - return MODELS.getModel(this.isPowered(), this.isActive()); + if (this.isActive() && this.isPowered()) { + return MODELS_HAS_CHANNEL; + } else if (this.isPowered()) { + return MODELS_ON; + } else { + return MODELS_OFF; + } } /** @@ -103,9 +110,8 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka */ @Override public void getBoxes(IPartCollisionHelper bch) { - bch.addBox(5, 5, 12, 11, 11, 13); - bch.addBox(3, 3, 13, 13, 13, 14); bch.addBox(2, 2, 14, 14, 14, 16); + bch.addBox(5, 5, 12, 11, 11, 14); } /** diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json index 62f3cea..43a1e58 100644 --- a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json @@ -1,6 +1,6 @@ { - "parent": "ae2:item/p2p_tunnel_base", + "parent": "ae2:item/cable_interface", "textures": { - "type": "extendedae_plus:part/entity_speed_ticker" + "front": "extendedae_plus:part/entity_speed_ticker_font" } } \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_has_channel.json b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_has_channel.json new file mode 100644 index 0000000..22f76cb --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_has_channel.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2:part/interface_has_channel" +} diff --git a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_off.json b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_off.json new file mode 100644 index 0000000..a31e532 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_off.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2:part/interface_off" +} diff --git a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_on.json b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_on.json new file mode 100644 index 0000000..9cfa323 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_on.json @@ -0,0 +1,3 @@ +{ + "parent": "ae2:part/interface_on" +} diff --git a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json index 3e091c5..687c196 100644 --- a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json +++ b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json @@ -1,6 +1,6 @@ { - "parent": "ae2:part/p2p/p2p_tunnel_base", + "parent": "ae2:part/interface_base", "textures": { - "type": "extendedae_plus:part/entity_speed_ticker" + "front": "extendedae_plus:part/entity_speed_ticker_font" } } \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker.png b/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker.png deleted file mode 100644 index 488c71509fbc6605dadde40bda3cfa267c38b969..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4259 zcmeHKeQXow89zfws0&jd7f8(H~Gs-W||)|V;DBmTk0-H_YD1-o`!xG42}SF>uId4 z(#k;$k3^NATnllnAp&t2mxCA z`n>Nqk*#>w^9Rlp|Ka4JefZGQ{@ue)&)t#O<14jzLRoODwlJ@p#apdzk zmoLv9E_pq6>hUF+gC;4<_Yt7|_YAD9>Yj7y+^P*Adt^vk-Z=F_M_{J6ZEqQdnKsBp zMSgEl(P%m-i8t1~;wtS~lGVGiqJx-|zW9ad!J5T=9#7Vr&7S@KOXha|^&fvV&G*pO z*$|I;Td-rGT`cY1=d&kgU z=70UviJe62lkb@4Ip_MD%%^TOjdb4#pYA`u`xmocoO*=nypw5~(zWEb;PSN-omY9& z@Y$o=F5LRlj-!8n`1(s*<`zuZ*tu@=z?L7}Ftsi|da}jx;MSZkWpgia^Jm4^UQOSq ztXpS4bZDrcY{A+^bsayQnw2%>!&z|OPY!o|&~@n9v+v!$Z5lily+niGe2LnwUPkRz z<$IDBm5>EUiU2L~Pz3cIhUGsNj{tEM)Nlb-%V8IBqw50#mn9dm!tSGeks??lmo`RW zMPpf|*tkk`O2lIY=KMI1076g$csx`aR{6M#FmQSFtcxiEH%zouE~3ik$BUFG#BCOv zg(f|5xt=8o%y@oO3i9Rd;v@uma}hO~7U3x>7K>S8R*Mp?rWmKwNzp9DvLvz~)rPPJ z;$&FO(IFBTZm5b;Iikr*7}qg@pwwwDf*8=Np3$t4S6RA5~>0Y#1!^H@OIY(Yp00>hD9kYzZ)IRx4&q(FJYss_R$)S(c#MMgMc zFb_DGphN;T=pbzZDl4D`Nai_$g1||vO%QA;5X+)6>Pk?X8kG(uAt;;O4j4OQBWbG> zMFZ_t(&+#+X|ppyjTm^!YiltZvW13I4!XSL_C9LsTxo#yP;aiirhs-j-hQ5o7|br>4GFg!{J zQ491=MF55zWy2RmA<&d)rJ~fj2t6oV_Z(CE&_GE*18$%}1WL0uo?&?_Q%Q5Yjo}&Y zQJUfD6njOIgAM=BS|1-gKT-5jSw-tN7^1{XRlwDWx5R6$Yzz~Q8)Lx(F_D4_>S2Oo zgq2W-WU`dLV~l2-PyG)c`G!Ht z7K8i}GPHG}osb&a3X^=HwZF?xvJT(n5;#7&$b|Tvq-&C{2{AAs(1I%cH_OH16?i2nWMkv%O)a&M$Gpkmm4_v@Dl+wsOc zBuv-5K2Q2*GZv&R%>0mjdJz&W^STQw9lsZ!nfI@?ncKxs=+4f0zLJ;cKQ|!$`uwy- z7w_5J+`Rvhe+~@vWbC>)Ek2XxxN3Agd<{F;gQb@n_cm7xSm8Wd_D*^Sik+RAy<3}P{)2yK;0#rA_Qq_hYXi(jSV)LE*qF zs{yRZR&b@! zFUP}y-LV|ny=9p1-o;&^-myVh-}Hc>CR3&~Yt?$Pd6*1x%6UBCmx<#pl*C_-OtYK5r3DPYOQ%|>*&PN4lu?W2F<;@*g@K#dC z)3o7f+SJrkampx0@tCH&uB&095rP1LlIeQNny8-i%`lW@!sD=!hEZL~7?~eUq$L$J zZJSVQG4a%jWrk0nc^csPoxGqJOEMmMFuUsx@p>3N}odqEV} z7;IZuV`EZl)W=%VDiv?Ao}{eKX(N*{mlNh% zu54=y>&p?J$U-Vx-_9-(ap1`J!egA;0kmj(9s7e+sUQ7NE6fRJ}GEKwmjBgE_ zvN}=@!D~rd5vzM<^wOEEj%E4j4TK3q+;peX49SN&Pt{Oqr6l;dZ353?Qwp^+9L~1E zJ-MKw9|JMJ{nE z5|$q50hhw?^F8b~W!7TQlPN?mlJ3gXUet>*JgQI1xGSg{EN0L`Wt^1MAdYGZYc#4M zZ)KJ?Sr?tolqaK-M#{y~GpEypjKi)7=$4YJp!|pO=8d=BDq-7^|KlcU+0md~0<=F@ zhxU89?a9sA-n3e-H(MR(H3p#vdr;QrDf9-GzD=C0ZBP?2okH*6jzriNltaS$PCKGA zw&>p$`YeX>@XEW;M(AW&nM^tr=1w-2*P0EpwlR{;ZJIW<;21)C<#I4L0-g9MAcP~`rUd*&Bv2dN!X|YL*Z(Wm-#J`#t!~9b zJGivVM_~)ub*hIDY7N0vA$!d4DDaZsa%3HPOAL3IeTScV6Yf7J2Fn|Vou@y1{*$F2 z;4Ak(@Z_nN$Ie|lsy3gw@9?&7mW--HV)5DA_U%~{_nmod|FsX|)uU(kJom`q7gm1y z)JJP?*n9FrT3LJi@#$Ar?7Mp5yBAiUc*|I*Z~pSv1s5LP+xOtHV^m4 z;A>twboR`S@Y9_u7VS;0`1Z+>ZTC++zWDX?yRKJ{zkTZbjqmJTvg6RvBggx0{rawx z@2!3RV?|wb?!Yho%XfcvV9l}X*6klSs66)Us++c*tguhagP>4WZ8f literal 0 HcmV?d00001 From b705a7c912d1060cfbc6bfb57943c451b4c6e6fe Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 11 Sep 2025 17:06:02 +0800 Subject: [PATCH 04/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../models/part/entity_speed_ticker_part.json | 5 ++++- .../part/entity_speed_ticker_back.png | Bin 0 -> 4005 bytes .../part/entity_speed_ticker_font.png | Bin 3632 -> 3844 bytes .../part/entity_speed_ticker_sides.png | Bin 0 -> 4022 bytes 4 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_back.png create mode 100644 src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_sides.png diff --git a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json index 687c196..df7a2d4 100644 --- a/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json +++ b/src/main/resources/assets/extendedae_plus/models/part/entity_speed_ticker_part.json @@ -1,6 +1,9 @@ { "parent": "ae2:part/interface_base", "textures": { - "front": "extendedae_plus:part/entity_speed_ticker_font" + "front": "extendedae_plus:part/entity_speed_ticker_font", + "sides": "extendedae_plus:part/entity_speed_ticker_sides", + "back": "extendedae_plus:part/entity_speed_ticker_back", + "particle": "extendedae_plus:part/entity_speed_ticker_back" } } \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_back.png b/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_back.png new file mode 100644 index 0000000000000000000000000000000000000000..3df8e9c2ff00e235ae65f243aa6af6b7e7193b73 GIT binary patch literal 4005 zcmc&%du$xV89xU^lMpIGR2o7l+fAf~CUZA4`(EV|9G_F0a8Bgdvco^=?Ch+)@!jpQ zyJw%>P_-4RTGdt6M^cHVqNJjLOT$x0RRp9;6(K=o)I#~Ai9*z-YK6c=kf5r9^xM1h z*#SGgw3T|&-R;i&=J!43d(3=ich8q^Sh;RxDwVpSyDQfV|2HPz<=4UQ?eAS;@VBDe zwKqzou3wXU+fol4UJKyUe&1j`n7`ZRK{3tTz!B+cu?*-`YRk52neh=3OO6=wOIdm5 z*o(5{yIFZa%j0~xLk#;}6QS5M(bLB#M!4n5+qOzusx}Z5Ma-mXu~3TaYF4iC+VGqV zXJn}ciAS<>dm>O8%20Snjnrbl?*Fwn2w<<=4Odvs%0?E5Q2zh6KrEsYJ6l6 z7rLI^o7>S425(t;IF8G9CNnlRmL5~mK{%8lmSrUzlp;W&XuK4&Dk??mXBl!L;-O!T z{h%ZzjLZotaaIOZ>oye2P1;h_@Dq3}Q)T50N#n$(8qnoUT)7e!YQkNf5d~2cr8ojC zX=1@m`Fs<;AZ@YOL`QMwC}`BMZ9#O@H(nN*UJ(VAkc-Yykhp$Uu_*2pbFOJ&Il!BX z%fmq&M8m-%PH0YF=8D+&77>`tTm}_Ye-UUh(}b4oj!>{T2>XJdFdIC(XLXZ0I;4#Q ze#s5SqB|0^8*q_hvB=60Mi^le5wnjHTd{1-+=Qu(aUGh6$aGoEnqUoK3lY*s3>y=h z=$o)P2M%1{8($LYa@z~SB7<%7i)=__%B7*2w0z#~E=4gbanYU2%Aji6_g&i*x}j1X zBZUf%G_DflV1kjZ=sH%JqiMQ6yFM52N)l4Z`g(e~0SAueUf9G{J!V)GIhMwds;MqA zE#ZM#oNAO3Vj9XU+pf@u3}=P;tcg}GFgn;1ii35eIJyV!OSGcQLd>Bq);-Tu6jhey z!%Fz18UqPimB%-V|D%-+jql0uf`r`_d85OL#;O0!4Y z+juJYQY|HI#_J~VBsPUBH-`NMHn=rc)@jFv1vu*pQCo*afftXlP_z$$hnL8S%wnoX zZ1l>CD~je(PgqE!SVf)#v1D1CA>lZ#X%S0dnm23sCl#l*ifs+grrXsk-f$@&W~Ctk z{U;;;=cZT!tDGwsao2Q^>!=p8sHGxTCm!**a22Pyhx1Lb5Y_vzVr$TYl&dm@k~E!P zndGVh8=a|{j8Ys(bERidr@12Z z=S9GLDNPlm|Dn7kPuVj~eB2I~!^i&aDgg zTC5SG5dl5YWE2@hRgvR4E^<|Bd5)(tuIO884lnpiakb)sR=HHlbZ8+45|+Z@9H9zi zLbZmnXL4*SWiDN3oGJ>!ipmf)eGPVo6C|(+M-5k1G2^Xr>6n`?)LS_1I|?!^ zAap=QWU9KyOgL{afm`J=;NrpH;D89TfKXLU+zCqH-RJ=1@`X?53z z7ruLF_3)FGZ{PCkO51JgpSrki)pZ>MH}_N~3Yk^uwcmQ@qYKAAn)%Y%ea{w0-gxWa zU(R>kwPJO94lB9evDYg3<=^(b;C!Fw<6-1Ol_@#tFzCJuc52h}4_?A&(O_2znMDfsC{>tm;9(&h+f9u9ioy_<5Kk&;h+<$!H`9lTy-IEtSIP%&% c=Rcdi_w9%FJ+$MNSeRI(=q4H@r|4Q(nwaTY8d@6brdk@BCmNZVB^f1ee$HISI{5&*=ww?q zMGqo009{aA;#yW>Ri2TWhtu{#c5P-eJ=4ka*%ddZa=u`$?>fHmIRgX3Sx*Hxh3ZozTV~BuvP4sgo*EDPNwHFa?ZWiH@98N5|^oAU`tr@%XC|x z!zq?)-<>SZf7Cn5XOShrP_lA?x8&`z={ggeuO8p7a_5uEp##@vhkP#f$f_^zb@xi- z+x==cOI_50_pJ;UZu)yWDY$XOiB&E0F7!Wt0C19g~#s8j$FD?<_K9LQ)C9;DuH__awFTM zg%oNq7+K$Yl7G6C63&dvDH?#&#WYPR#)x^I4}lN@y!RN#u`>cOM%?-V_kMsQYQn+{ z0NBDYY0h8|1Aud61m}uaQC)S22Bzz479z&9)$1F!fCyK)zq`gG zC*eoay(z%VAR+_kn)yQude53D!WArqNUk7+kP{qH(@kN`H3HsyZ0qv%Q`XV_{Wm@V X`Ak^$5|?`h00000NkvXXu0mjf6)=NL diff --git a/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_sides.png b/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_sides.png new file mode 100644 index 0000000000000000000000000000000000000000..441a7c1d6941cff20da538aaeb5ddc9fb716a125 GIT binary patch literal 4022 zcmc&%4U8OB9pBbe%GCl_Y&jIlWT;X~-|m|?-{URhxIKE8cF*&=wb#ZE-n@BpH{9;b zIy3i4v`t%#kW?UzM(d>}SmY}xqNdnV+uA769)i}W3Dhbv5rf)bm7+1!|LpGVUE!{` zRTDSa-I@1(@Av-y|NDQvdwaUqEp2*VQ!15O+SQrsh5xIP@8WmE?+s_qQ~0~Q+_@!6 zrIuWsd>5qlPP72{lvn7B`|=ws7L?M|32dGoEtLVCO10iLTBdA}$AZoKJwGd+Idnu6 zJSQt|R`WPtZs!AD=Xl6Bj&~Q>_#iVK@wQuq)=>)xN<5~*XsPH&)@W9&@LKSk3}-~4 z0*ME+Vq3DI(3kHK+Jle_W?DiFVkql941NnU;htYzVcF2-}5@ zYxU;tsBH#sS#cna%T^{cGBT1Lk<&rgpOH+{OgIQZfI!ihAJb9fM>kF}iA4u;~a2%=VXD3$B9epIs)SS&M2%NZ$+6P+qRht+ZAp|Dul++i7BRPE?-+(1Z=4b=ihKFAX&P7#@cQEN zKoAGfKrn|9>eCmPBKF)lHcVzNfbvmq4rnq{hnB7OkkdE_3qeqva-NK^mHjtD<^lmURh8A+c#k*Ai+wo{tQJ)T(PqwUxo{>)WJ!Elon8bUH&)9u8~LYd zPeo6tgrr4TRRxy#CI^#NhrL-2xG_^!*N+TvFxEx9whD^^Hy)uOZ|esO&l3}wxkQiX z@Wlm}Wz{7vH<3!Pf?Qj1kZCfCxNSRzDVZ`=-6_T2DLAndY^iuE+%8@4nn~FJ_4_&0 zpN#mQt73AjFeYQf9K%MAt(XvGrh*(zawV5>N4D!{I8zl95v_n_ONAOFUy>?BN|TwH zsj7b?%CNv6=HU#dD$|fc4dr2!72Pl>3A9`;daM#znPK0lRi=6{3UMGzr=B^D=J3#) z;Q=#usf!@|5BHnb-)zoh!iWP7#vyG{#YTq8b)-^iGDtoeoZ@W$_WwAfd6j7_t-mem z=PEx91rO2E>bxG8N&1{>KFhp4)m7hfRkye!akNVRV9l1)8Vx9DC@iQ^^HePvb6Y1y za`K9bsFYMKW^jacM`4hCY@-^U30v^rR;?r;>ak)?6~8tp%Sq0UYU%QJ+Fwtcx6V;( zRY_7M4mHxC1nH8ZAltPaF1-d3%k~BmOT~&2OgG{0{%4J|CyArXHO9(@f zt`M*nbWakMnTA!xkWKrYT$j=*%~)OWhpKaBF7AaD!M3hkTfx}<={?`_e}J$0?D_RO3pYRa`Bw*jzhH9fkF^{=fYEK+V)?u;ZJ>&t*IB&Pbo}s&=C-ZB8d|;b{&g+v&L@BP)|)FX?;AY6ul0qUdz2GT zKlS65t0xMZ?pf8f;~A}miFEIV4?grj{1gAclIO)`xuH|$HAjD5)b>2``iH*1cgY*4 zgGV1ko-VLwZ_1*iNdlwIV{J42d{@cH_jqBd{*#7*< zzonOzA3n9T`PlEupUW(hFMHzPZzqnQJ-+T2|N7%6dfvO}udVk_>_7XDiS4fqK6_8} z)urP{<2BpQfAVYRR(|E=)8{7s-g4l&&!m(qUOs59{oZhLv+nBX&VA$dJ9qpW&V4oK literal 0 HcmV?d00001 From 255b8aeb1c0234d4ccfddec16fa0bc1322c42645 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 11 Sep 2025 17:13:39 +0800 Subject: [PATCH 05/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8=E6=96=87=E4=BB=B6=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/extendedae_plus/ExtendedAEPlus.java | 4 ++-- .../{ => ae}/items/EntitySpeedTickerPartItem.java | 2 +- .../extendedae_plus/{ => ae}/menu/EntitySpeedTickerMenu.java | 4 ++-- .../com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java | 2 +- .../{ => ae}/screen/EntitySpeedTickerScreen.java | 4 ++-- src/main/java/com/extendedae_plus/init/ModItems.java | 2 +- src/main/java/com/extendedae_plus/init/ModMenuTypes.java | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) rename src/main/java/com/extendedae_plus/{ => ae}/items/EntitySpeedTickerPartItem.java (89%) rename src/main/java/com/extendedae_plus/{ => ae}/menu/EntitySpeedTickerMenu.java (96%) rename src/main/java/com/extendedae_plus/{ => ae}/screen/EntitySpeedTickerScreen.java (94%) diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 416740e..9a3ffd6 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -2,13 +2,13 @@ package com.extendedae_plus; import appeng.init.client.InitScreens; import appeng.menu.locator.MenuLocators; +import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; +import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.client.ClientProxy; import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.*; -import com.extendedae_plus.menu.EntitySpeedTickerMenu; import com.extendedae_plus.menu.locator.CuriosItemLocator; import com.extendedae_plus.network.ModNetwork; -import com.extendedae_plus.screen.EntitySpeedTickerScreen; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; diff --git a/src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java b/src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java similarity index 89% rename from src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java rename to src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java index 011cebf..7cb982d 100644 --- a/src/main/java/com/extendedae_plus/items/EntitySpeedTickerPartItem.java +++ b/src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java @@ -1,4 +1,4 @@ -package com.extendedae_plus.items; +package com.extendedae_plus.ae.items; import appeng.items.parts.PartItem; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; diff --git a/src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java similarity index 96% rename from src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java rename to src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index 7b93fb9..0531741 100644 --- a/src/main/java/com/extendedae_plus/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -1,11 +1,11 @@ -package com.extendedae_plus.menu; +package com.extendedae_plus.ae.menu; import appeng.core.definitions.AEItems; import appeng.menu.implementations.UpgradeableMenu; import appeng.menu.slot.OptionalFakeSlot; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; +import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.init.ModMenuTypes; -import com.extendedae_plus.screen.EntitySpeedTickerScreen; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Inventory; diff --git a/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java b/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java index 87c7ed3..91d5b52 100644 --- a/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java +++ b/src/main/java/com/extendedae_plus/ae/parts/EntitySpeedTickerPart.java @@ -18,8 +18,8 @@ import appeng.menu.locator.MenuLocators; import appeng.parts.PartModel; import appeng.parts.automation.UpgradeablePart; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; import com.extendedae_plus.init.ModMenuTypes; -import com.extendedae_plus.menu.EntitySpeedTickerMenu; import com.extendedae_plus.util.PowerUtils; import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java similarity index 94% rename from src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java rename to src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java index 8929071..eb37978 100644 --- a/src/main/java/com/extendedae_plus/screen/EntitySpeedTickerScreen.java +++ b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java @@ -1,8 +1,8 @@ -package com.extendedae_plus.screen; +package com.extendedae_plus.ae.screen; import appeng.client.gui.implementations.UpgradeableScreen; import appeng.client.gui.style.ScreenStyle; -import com.extendedae_plus.menu.EntitySpeedTickerMenu; +import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; import com.extendedae_plus.util.PowerUtils; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index d3ddcb2..c3ee08c 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -4,7 +4,7 @@ import appeng.api.parts.IPart; import appeng.api.parts.PartModels; import appeng.items.parts.PartModelsHelper; import com.extendedae_plus.ExtendedAEPlus; -import com.extendedae_plus.items.EntitySpeedTickerPartItem; +import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraftforge.registries.DeferredRegister; diff --git a/src/main/java/com/extendedae_plus/init/ModMenuTypes.java b/src/main/java/com/extendedae_plus/init/ModMenuTypes.java index 238ad40..bd1de78 100644 --- a/src/main/java/com/extendedae_plus/init/ModMenuTypes.java +++ b/src/main/java/com/extendedae_plus/init/ModMenuTypes.java @@ -2,8 +2,8 @@ package com.extendedae_plus.init; import appeng.menu.implementations.MenuTypeBuilder; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; -import com.extendedae_plus.menu.EntitySpeedTickerMenu; import com.extendedae_plus.menu.NetworkPatternControllerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraftforge.common.extensions.IForgeMenuType; From 0d9edb67737fe3b94828aba5c37c594b9950f75a Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 11 Sep 2025 20:36:21 +0800 Subject: [PATCH 06/44] =?UTF-8?q?feat:=20=E4=BF=AE=E6=94=B9=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8=E7=BA=B9=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../part/entity_speed_ticker_back.png | Bin 4005 -> 4001 bytes .../part/entity_speed_ticker_font.png | Bin 3844 -> 3846 bytes .../part/entity_speed_ticker_sides.png | Bin 4022 -> 4023 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_back.png b/src/main/resources/assets/extendedae_plus/textures/part/entity_speed_ticker_back.png index 3df8e9c2ff00e235ae65f243aa6af6b7e7193b73..d74b5fe1375c96fc3122ac8ff9bd97268ad20d15 100644 GIT binary patch delta 562 zcmZ1~zfgWdG&8$}m7%GXfyLw`W)(QQm)SxkH7(IFDK#lk*EG$@MAz8Z#8fxY#Mn^R zC?(n4%rx23!T_l0C9{@_sgY%}d0L8zu8EOFnr@nbNwTg*qOpapaf*qtrD2Mpv2jw; zW^`e_>qwC$H{eYCK2Zt#RQ zTZbU)oo+=855!d1Psk;km+A>sc}dm|DN`|BOa@#zODZ^^Z)mVAAQR* z-;`Kwy#3ZgQ&FjdBdx8&qDMkGG<0LsT9$+-?3$_#a~_c4hJp(N#<0iMCcSdis^*tmiYW`iO^lOzS_D4b+8@tea6k;-+%tj|DTphci(?cOFL1v+w{K8{PQ&`t5z{ptW2|;KYJCE!Cb#c9WkE6 z4%bUpWbNCSDV5YS$4^~vy7#(>(5X{`zC9@2B>biJyaCTnuKVHUX{NUsFO=Tpc(Bxp z^FY?N(`l=i?`*i_BY5!X)blSRjDP>{S)X73dB3;zUyaliuWPDmLqlgRQ*1d*MUP&cEruHuZtT$OMdWEb~^`7|n{mpa!VonD{cgHSbd{TIETkeKy zi(c;vJ|Mxo)^ygglQSB&iXAR?`CIcq?}(yJbw8u>t9`eUZgXrbYDrx<YVTGSNU1*SUHMyF&4hP z#;<(l-e#BWKAbYeLX62iN=|d%9gQ(-x+YZ`U;B5;;?(;8z4}ffiDz!E^$rI5jlt8^ K&t;ucLK6V()0U_J delta 403 zcmZpZYmwU!&CG6QWol++XfQd6Sq0ASWwuZ;H%c_HFtJF{O*BYO(Y3HNG1Ij)v^3UD zwKOzOG%_{E}HqB{A8=JT2KgRo5)VBuO^~L?juQChJ-l8Kxzsq#76)8yRml zXGvux&d39tQZRRHe#mLXQr~ra<8uZEhO?e7jv*GkM}r-?nhgYGx|eNKZFiD?%)aL- z_ugL`_aC0+{~^uq$n$YR+^$X8E?i=}HVBlJrJ1@BuKF5L9@c2aQT zh!d+?=3}_ZlViPqG&8$}m7%efk>%thW)(QQm)Sxk&CDRhBsDoj*T~G+P&dWQBtB~^3!Y1T76f9v?u+P=#%IK_#u-rD9mEj40o7z@Knu9Dd0nlmK*^MmgktFNr( zvJ`B!(LEisYh8EOz3Q5}SY^giWhI7&yLswLOZ$AKv6Z%-=a z<}8Vv*6Mp~#)Bp6vQ<2Vj%+$4t0&Nibi#bB5SNg;lT5?PQoH*4=8e*Z1Sk z(xbqU5d{`_{g zLuZK$jsP6*T6K{Sl2Yw#6s87$kbHV z%-F~z)yTj+$s)yY@=Ind6@wIuR3oFbMBQXdqf}iZQxjv|BqMWU-NYo*lr-~H15-nb zl+ETWsjS2qd4N+2=8nw|Ijvag%lGn!GB7aKd%8G=SoGFT-k5jDK%nivcXNp5@xB+? zPZ-Zcotd}NnSH{pk4&<^nC@yhF5&Ze6LH3d;k;wnBaf*8#j-CVEdr~({nGE(@85r; z<-W%0pmWcSXGq?DD|UwGy)8q_9t|!N-)5cD8zOW#7=lDIZifXM7|%QQen;=w%zDWp zC9cY-X-l`{N{jCO{v%6oV#6*$L52fWd&LADqpp`~$o0ERBqyvr`tOGrXGHelc{b;p zC!3t!wBe+L@SKp)Ru#{t9cB{AN{O?4)D}%BIhD7a`>c|XOX*!p@dKA~%qB1YXuWS1 z_qY4`D^_VSsVYsJd@-Zt`0nsK>C8EP-YQ)6%e^Di)jfp{zHai}?J9a<{l9y9{JkwR zt6i14-mwa@%56V*rrud)(S;Rx%PwciKg!zLmD0&k8hhAM+;{V}Bnz2uF-v?ef6)^v zSbCRN@ZiIO4t*hG_SL%{%sKq|u=|xiFXIA4SU=hH&sp;M=bVPu*?U@x=krz_DA8*8 pAHVp!+-$kao4(KaDzROrj=_ZQ&Mr%xon;I_;OXk;vd$@?2>=vK=>z}( From 4a02c5bf4266edee705c0528d55e5260b5a8d3ea Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 00:33:48 +0800 Subject: [PATCH 07/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae/menu/EntitySpeedTickerMenu.java | 22 +++ .../ae/parts/EntitySpeedTickerPart.java | 27 ++- .../ae/screen/EntitySpeedTickerScreen.java | 2 + .../extendedae_plus/config/ModConfigs.java | 22 ++- .../util/ConfigParsingUtils.java | 158 ++++++++++++++++++ .../com/extendedae_plus/util/PowerUtils.java | 2 +- .../ae2/screens/entity_speed_ticker.json | 8 + .../assets/extendedae_plus/lang/en_us.json | 4 +- .../assets/extendedae_plus/lang/zh_cn.json | 1 + 9 files changed, 239 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index 0531741..270131d 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -5,9 +5,13 @@ import appeng.menu.implementations.UpgradeableMenu; import appeng.menu.slot.OptionalFakeSlot; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; +import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.ModMenuTypes; +import com.extendedae_plus.util.ConfigParsingUtils; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.registries.ForgeRegistries; // 实体加速器菜单,负责与客户端界面同步数据 public class EntitySpeedTickerMenu extends UpgradeableMenu { @@ -15,6 +19,8 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu * 该部件可以加速目标方块实体的 tick 速率,消耗 AE 网络能量,并支持加速卡升级

@@ -165,12 +172,19 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka return; } -// String id = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString(); - // 获取方块实体的位置 BlockPos pos = blockEntity.getBlockPos(); if (blockEntity.getLevel() == null) return; + // 检查黑名单(支持通配符/正则) + String blockId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString(); + + // 使用工具类的缓存接口(工具类内部负责懒加载/线程安全) + List compiledBlacklist = ConfigParsingUtils.getCachedBlacklist(ModConfigs.EntitySpeedTickerBlackList.get()); + for (Pattern p : compiledBlacklist) { + if (p.matcher(blockId).matches()) return; + } + // 获取该方块实体的 Ticker @SuppressWarnings("unchecked") BlockEntityTicker blockEntityTicker = this.getLevel() @@ -191,6 +205,15 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka // 使用工具类统一计算增长因子与原始功耗,并从网络中抽取对应能量 double requiredPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); + double multiplier = 1.0; + for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(ModConfigs.EntitySpeedTickerMultipliers.get())) { + if (me.pattern.matcher(blockId).matches()) { + multiplier = Math.max(multiplier, me.multiplier); + } + } + + requiredPower *= multiplier; + // 先模拟提取以检查网络中是否有足够能量,再真正抽取 double simulated = getMainNode().getGrid().getEnergyService() .extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG); diff --git a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java index eb37978..3bbe7e1 100644 --- a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java +++ b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java @@ -27,6 +27,7 @@ public class EntitySpeedTickerScreen extends Up private void textData() { int speedCardCount = getMenu().speedCardCount; int energyCardCount = getMenu().energyCardCount; + double multiplier = getMenu().multiplier; double finalPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); int speed = PowerUtils.getSpeedMultiplier(speedCardCount); @@ -35,5 +36,6 @@ public class EntitySpeedTickerScreen extends Up setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", speed)); setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", PowerUtils.formatPower(finalPower))); setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); + setTextContent("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", multiplier))); } } \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/config/ModConfigs.java b/src/main/java/com/extendedae_plus/config/ModConfigs.java index a746b53..623ab8d 100644 --- a/src/main/java/com/extendedae_plus/config/ModConfigs.java +++ b/src/main/java/com/extendedae_plus/config/ModConfigs.java @@ -12,7 +12,9 @@ public final class ModConfigs { public static final ForgeConfigSpec.BooleanValue PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT; public static final ForgeConfigSpec.IntValue SMART_SCALING_MAX_MULTIPLIER; public static final ForgeConfigSpec.IntValue SMART_SCALING_MIN_BENEFIT_FACTOR; - public static final ForgeConfigSpec.IntValue EntityTickerCost; + public static final ForgeConfigSpec.IntValue EntitySpeedTickerCost; + public static final ForgeConfigSpec.ConfigValue> EntitySpeedTickerBlackList; + public static final ForgeConfigSpec.ConfigValue> EntitySpeedTickerMultipliers; static { @@ -81,10 +83,26 @@ public final class ModConfigs { .define("patternTerminalShowSlotsDefault", true); - EntityTickerCost = builder + builder.push("EntitySpeedTicker"); + EntitySpeedTickerCost = builder .comment("实体加速器的能量消耗基础值") .defineInRange("EntityTickerCost", 512, 0, Integer.MAX_VALUE); + EntitySpeedTickerBlackList = builder + .comment( + "实体加速器黑名单:匹配的方块将不会被加速。支持通配符/正则(例如:minecraft:*)", + "格式:全名或通配符/正则字符串,例如 'minecraft:chest'、'minecraft:*'、'modid:.*_fluid'" + ) + .defineList("EntityTickerBlackList", java.util.List.of(), o -> o instanceof String); + + EntitySpeedTickerMultipliers = builder + .comment( + "额外消耗倍率配置:为某些方块设置额外能量倍率,格式 'modid:blockid multiplier',例如 'minecraft:chest 2x'", + "支持通配符/正则匹配(例如 'minecraft:* 2x' 会对整个命名空间生效)。" + ) + .defineList("EntityTickerMultipliers", java.util.List.of(), o -> o instanceof String); + builder.pop(); + builder.pop(); COMMON_SPEC = builder.build(); } diff --git a/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java b/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java new file mode 100644 index 0000000..b9377a5 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java @@ -0,0 +1,158 @@ +package com.extendedae_plus.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * 配置解析工具类:用于解析黑名单与倍率配置的字符串 + */ +public final class ConfigParsingUtils { + private ConfigParsingUtils() {} + + public static final class MultiplierEntry { + public final Pattern pattern; + public final double multiplier; + + public MultiplierEntry(Pattern pattern, double multiplier) { + this.pattern = pattern; + this.multiplier = multiplier; + } + } + + /** + * 编译用户提供的匹配串。支持简单的 glob 语法('*' 和 '?')以及完整的正则表达式。 + * 规则: + * - 如果字符串包含 ".*" 或其他正则元字符,优先尝试按正则编译(若失败则回退到 glob 转换)。 + * - 否则若包含 '*' 或 '?',将按 glob 语法转换为正则。 + * - 否则按字面量匹配处理。 + */ + public static Pattern compilePattern(String raw) { + if (raw == null) throw new IllegalArgumentException("pattern is null"); + raw = raw.trim(); + if (raw.isEmpty()) throw new IllegalArgumentException("pattern is empty"); + + // If it looks like regex (contains '.*' or regex metachar), try regex first + if (raw.contains(".*") || raw.matches(".*[\\[\\(\\+\\{\\\\].*")) { + try { + return Pattern.compile("^" + raw + "$"); + } catch (PatternSyntaxException ignored) { + // fallback to glob below + } + } + + // If contains glob chars, convert to regex + if (raw.contains("*") || raw.contains("?")) { + StringBuilder sb = new StringBuilder(); + sb.append('^'); + for (char c : raw.toCharArray()) { + switch (c) { + case '*': sb.append(".*"); break; + case '?': sb.append('.'); break; + default: + // escape regex special chars + if (".\\+[]{}()^$|".indexOf(c) >= 0) { + sb.append('\\'); + } + sb.append(c); + } + } + sb.append('$'); + return Pattern.compile(sb.toString()); + } + + // Otherwise treat as a literal (match exact) + return Pattern.compile("^" + Pattern.quote(raw) + "$"); + } + + /** + * Parse multiplier entries like 'modid:block 2x' into MultiplierEntry objects. + * Accepts values with optional trailing 'x' (case-insensitive). + */ + public static MultiplierEntry parseMultiplierEntry(String entry) { + if (entry == null) return null; + String[] parts = entry.trim().split("\\s+"); + if (parts.length < 2) return null; + String key = parts[0]; + String val = parts[1].toLowerCase(); + if (val.endsWith("x")) val = val.substring(0, val.length() - 1); + double m; + try { + m = Double.parseDouble(val); + } catch (NumberFormatException ex) { + return null; + } + try { + Pattern p = compilePattern(key); + return new MultiplierEntry(p, m); + } catch (IllegalArgumentException e) { + return null; + } + } + + public static List compilePatterns(List raw) { + List out = new ArrayList<>(); + if (raw == null) return out; + for (String s : raw) { + if (s == null || s.isBlank()) continue; + try { out.add(compilePattern(s)); } catch (IllegalArgumentException ignored) {} + } + return out; + } + + public static List parseMultiplierList(List raw) { + List out = new ArrayList<>(); + if (raw == null) return out; + for (String s : raw) { + MultiplierEntry me = parseMultiplierEntry(s); + if (me != null) out.add(me); + } + return out; + } + + // ------------------ 全局缓存与接口 ------------------ + private static volatile List cachedBlacklist = null; + private static volatile List cachedMultiplierEntries = null; + private static final Object CACHE_LOCK = new Object(); + + /** + * 获取已解析并缓存的黑名单(线程安全、懒加载)。 + */ + public static List getCachedBlacklist(java.util.List source) { + if (cachedBlacklist == null) { + synchronized (CACHE_LOCK) { + if (cachedBlacklist == null) { + cachedBlacklist = compilePatterns(source); + } + } + } + return java.util.List.copyOf(cachedBlacklist); + } + + /** + * 获取已解析并缓存的倍率列表(线程安全、懒加载)。 + */ + public static List getCachedMultiplierEntries(java.util.List source) { + if (cachedMultiplierEntries == null) { + synchronized (CACHE_LOCK) { + if (cachedMultiplierEntries == null) { + cachedMultiplierEntries = parseMultiplierList(source); + } + } + } + return java.util.List.copyOf(cachedMultiplierEntries); + } + + /** + * 清空缓存,下一次获取时将重新从提供的源解析(或调用方可以重新调用 getter)。 + */ + public static void reload() { + synchronized (CACHE_LOCK) { + cachedBlacklist = null; + cachedMultiplierEntries = null; + } + } +} + + diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java index ef42443..067af5c 100644 --- a/src/main/java/com/extendedae_plus/util/PowerUtils.java +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -37,7 +37,7 @@ public final class PowerUtils { * @return 原始能耗 */ public static double getRawPower(int speedCardCount) { - double base = ModConfigs.EntityTickerCost.get(); + double base = ModConfigs.EntitySpeedTickerCost.get(); return base * getGrowthFactor(speedCardCount); } diff --git a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json index acde6c9..64dfc30 100644 --- a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json +++ b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json @@ -44,6 +44,14 @@ }, "align": "CENTER" } + , + "multiplier": { + "position": { + "top": 90, + "left": 88 + }, + "align": "CENTER" + } }, "widgets": { "toolbox": { diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 93331f1..b112fd2 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -3,6 +3,7 @@ "screen.extendedae_plus.entity_speed_ticker.energy": "Energy Usage: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power ratio: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d", + "screen.extendedae_plus.entity_speed_ticker.multiplier": "Extra consumption multiplier: %s", "gui.expatternprovider.toggle_slots": "Toggle Slots", "gui.expatternprovider.hide_slots": "Hide Slots", @@ -29,8 +30,7 @@ "config.jade.plugin_extendedae_plus.wt_network_usable": "Show Network Online State", "extendedae_plus.tooltip.frequency": "Frequency: %d", "extendedae_plus.tooltip.master_mode": "Mode: %s", - "extendedae_plus.tooltip.locked": "Locked: %s" - , + "extendedae_plus.tooltip.locked": "Locked: %s", "screen.extendedae_plus.title": "ExtendedAE Plus Config", "config.extendedae_plus.pageMultiplier": "Pattern Provider Page Multiplier", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 09eadc2..619b23f 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -33,6 +33,7 @@ "screen.extendedae_plus.entity_speed_ticker.energy": "能耗: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "功耗比例: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d", + "screen.extendedae_plus.entity_speed_ticker.multiplier": "额外消耗倍率: %s", "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "无线收发器信息", "config.jade.plugin_extendedae_plus.wt_frequency": "显示频率", From 9d98324078c099ef2097f14fb2dcd486e86d5a82 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 00:41:04 +0800 Subject: [PATCH 08/44] =?UTF-8?q?feat:=20=E6=8C=89zh=5Fcn.json=E9=A1=BA?= =?UTF-8?q?=E5=BA=8F=E8=A1=A5=E5=85=A8=E5=B9=B6=E6=95=B4=E7=90=86en=5Fus.j?= =?UTF-8?q?son=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../assets/extendedae_plus/lang/en_us.json | 62 +++++++++++++------ 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index b112fd2..768e2f4 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -1,27 +1,48 @@ { + "gui.expatternprovider.toggle_slots": "Toggle Slots", + "gui.expatternprovider.hide_slots": "Hide Slots", + "gui.expatternprovider.show_slots": "Show Slots", + "gui.expatternprovider.clear_selection": "Clear Selection", + "gui.extendedae_plus.global.toggle_blocking": "Toggle Blocking Mode", + "gui.extendedae_plus.global.toggle_adv_blocking": "Toggle Advanced Blocking", + "gui.extendedae_plus.global.toggle_smart_doubling": "Toggle Smart Doubling", + "gui.extendedae_plus.global.all_on": "All On", + "gui.extendedae_plus.global.all_off": "All Off", + + "itemGroup.extendedae_plus.main": "ExtendedAE Plus", + "item.extendedae_plus.wireless_transceiver": "Wireless Transceiver", + "item.extendedae_plus.4x_crafting_accelerator": "4x Crafting Accelerator", + "item.extendedae_plus.16x_crafting_accelerator": "16x Crafting Accelerator", + "item.extendedae_plus.64x_crafting_accelerator": "64x Crafting Accelerator", + "item.extendedae_plus.256x_crafting_accelerator": "256x Crafting Accelerator", + "item.extendedae_plus.1024x_crafting_accelerator": "1024x Crafting Accelerator", + "item.extendedae_plus.network_pattern_controller": "Pattern Supplier State Controller", + + "block.extendedae_plus.wireless_transceiver": "Wireless Transceiver", + "block.extendedae_plus.4x_crafting_accelerator": "4x Crafting Accelerator", + "block.extendedae_plus.16x_crafting_accelerator": "16x Crafting Accelerator", + "block.extendedae_plus.64x_crafting_accelerator": "64x Crafting Accelerator", + "block.extendedae_plus.256x_crafting_accelerator": "256x Crafting Accelerator", + "block.extendedae_plus.1024x_crafting_accelerator": "1024x Crafting Accelerator", + "block.extendedae_plus.network_pattern_controller": "Pattern Supplier State Controller", + + "extendedae_plus.upload_to_matrix": "Upload to Assembly Matrix", + "extendedae_plus.upload_to_matrix.success": "Pattern uploaded to the assembly matrix", + "extendedae_plus.upload_to_matrix.fail_not_crafting": "Only crafting patterns are supported; processing patterns will be ignored", + "extendedae_plus.upload_to_matrix.fail_no_matrix": "No formed assembly matrix found in the current network", + "extendedae_plus.upload_to_matrix.fail_full": "The assembly matrix pattern inventory is full or cannot insert", + "extendedae_plus.screen.reload_mapping": "Reload Mapping", + "extendedae_plus.screen.add_mapping": "Add Mapping", + "extendedae_plus.screen.cn_name": "Chinese Name", + "extendedae_plus.button.choose_provider": "Upload Pattern", + "extendedae_plus.pattern.hovertext.player": "Encoded by %s", + "item.extendedae_plus.entity_speed_ticker": "Entity Speed Ticker", "screen.extendedae_plus.entity_speed_ticker.energy": "Energy Usage: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power ratio: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d", "screen.extendedae_plus.entity_speed_ticker.multiplier": "Extra consumption multiplier: %s", - "gui.expatternprovider.toggle_slots": "Toggle Slots", - "gui.expatternprovider.hide_slots": "Hide Slots", - "gui.expatternprovider.show_slots": "Show Slots", - "gui.expatternprovider.clear_selection": "Clear Selection", - "gui.extendedae_plus.pattern_provider.select": "Select Pattern Provider", - "gui.extendedae_plus.pattern_provider.selected": "Pattern Provider Selected", - "gui.extendedae_plus.pattern_provider.unselected": "Click to select this pattern provider", - "message.extendedae_plus.no_provider_selected": "Please select a pattern provider first", - "message.extendedae_plus.invalid_pattern": "Please hold a valid encoded pattern", - "message.extendedae_plus.upload_success": "Pattern uploaded successfully", - "message.extendedae_plus.upload_failed": "Failed to upload pattern - no empty slots", - "message.extendedae_plus.uploading_pattern": "Uploading pattern...", - "gui.extendedae_plus.group_header.choice": "Toggle Group Choice", - "gui.extendedae_plus.group_header.choiceable": "Group is choiceable", - "gui.extendedae_plus.group_header.not_choiceable": "Group is not choiceable", - "itemGroup.extendedae_plus.main": "ExtendedAE Plus", - "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "Wireless Transceiver Info", "config.jade.plugin_extendedae_plus.wt_frequency": "Show Frequency", "config.jade.plugin_extendedae_plus.wt_master_mode": "Show Master/Slave Mode", @@ -31,6 +52,7 @@ "extendedae_plus.tooltip.frequency": "Frequency: %d", "extendedae_plus.tooltip.master_mode": "Mode: %s", "extendedae_plus.tooltip.locked": "Locked: %s", + "screen.extendedae_plus.title": "ExtendedAE Plus Config", "config.extendedae_plus.pageMultiplier": "Pattern Provider Page Multiplier", @@ -41,7 +63,9 @@ "config.extendedae_plus.providerRoundRobinEnable": "Enable Provider Round-Robin (Smart Doubling)", "config.extendedae_plus.state_on": "On", "config.extendedae_plus.state_off": "Off", + "config.extendedae_plus.showEncoderPatternPlayer": "Show Encoded Pattern Player", + "config.extendedae_plus.patternTerminalShowSlotsDefault": "Pattern Terminal Show Slots By Default", "config.extendedae_plus.smartScalingMaxMultiplier": "Smart Scaling Max Multiplier", - "config.extendedae_plus.smartScalingMaxMultiplier_with_range": "Smart Scaling Max Multiplier (0 = Unlimited)" - ,"config.extendedae_plus.smartScalingMinBenefitFactor": "Smart Scaling Min Benefit Factor (default 4)" + "config.extendedae_plus.smartScalingMaxMultiplier_with_range": "Smart Scaling Max Multiplier (0 = Unlimited)", + "config.extendedae_plus.smartScalingMinBenefitFactor": "Smart Scaling Min Benefit Factor (default 4)" } \ No newline at end of file From ac58fc66bdddef6909944c22452bc53385be05e1 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 00:53:28 +0800 Subject: [PATCH 09/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 21 +++++++------------ .../client/ClientModelEvents.java | 2 +- ...{ClientProxy.java => ClientRegistrar.java} | 16 ++++++++++++-- 3 files changed, 22 insertions(+), 17 deletions(-) rename src/main/java/com/extendedae_plus/client/{ClientProxy.java => ClientRegistrar.java} (83%) diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 9a3ffd6..62a0d6b 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -1,10 +1,7 @@ package com.extendedae_plus; -import appeng.init.client.InitScreens; import appeng.menu.locator.MenuLocators; -import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; -import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; -import com.extendedae_plus.client.ClientProxy; +import com.extendedae_plus.client.ClientRegistrar; import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.*; import com.extendedae_plus.menu.locator.CuriosItemLocator; @@ -37,7 +34,7 @@ public class ExtendedAEPlus { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); // 在客户端尽早注册内置模型,保证首次资源加载前映射已建立(仿照 AE2 的 AppEngClient 构造期注册) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientProxy::initBuiltInModels); + DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientRegistrar::initBuiltInModels); // 注册mod初始化事件 modEventBus.addListener(this::commonSetup); @@ -57,9 +54,6 @@ public class ExtendedAEPlus { // 注册通用配置 ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); - - // 客户端侧延迟注册:在 FMLClientSetupEvent 阶段执行(包含 MenuScreens 绑定等) - // 由下面的 ClientModEvents 负责在客户端总线上接收事件并委派 } /** @@ -97,20 +91,19 @@ public class ExtendedAEPlus { public static void onClientSetup(final FMLClientSetupEvent event) { // 直接在此处执行客户端一次性注册(UI/屏幕/渲染器绑定) // 注册客户端配置界面 - ClientProxy.registerConfigScreen(); + ClientRegistrar.registerConfigScreen(); - InitScreens.register(ModMenuTypes.ENTITY_TICKER_MENU.get(), - EntitySpeedTickerScreen::new, - "/screens/entity_speed_ticker.json"); + // 将 InitScreens 的注册委托给 ClientRegistrar,便于集中管理客户端注册逻辑 + ClientRegistrar.registerInitScreens(); // 菜单 -> 屏幕 绑定 - ClientProxy.registerMenuScreens(); + ClientRegistrar.registerMenuScreens(); } @SubscribeEvent public static void onRegisterGeometryLoaders(final ModelEvent.RegisterGeometryLoaders evt) { try { - ClientProxy.initBuiltInModels(); + ClientRegistrar.initBuiltInModels(); // 注册 AE2 部件模型(例如 entity_ticker_part_item),仿照 CrazyAddons 的做法 ModItems.registerPartModels(); } catch (Exception ignored) {} diff --git a/src/main/java/com/extendedae_plus/client/ClientModelEvents.java b/src/main/java/com/extendedae_plus/client/ClientModelEvents.java index fa441d1..e62450d 100644 --- a/src/main/java/com/extendedae_plus/client/ClientModelEvents.java +++ b/src/main/java/com/extendedae_plus/client/ClientModelEvents.java @@ -22,6 +22,6 @@ public final class ClientModelEvents { event.register(ExtendedAEPlus.id("block/crafting/64x_accelerator_formed_v2")); event.register(ExtendedAEPlus.id("block/crafting/256x_accelerator_formed_v2")); event.register(ExtendedAEPlus.id("block/crafting/1024x_accelerator_formed_v2")); - ClientProxy.initBuiltInModels(); + ClientRegistrar.initBuiltInModels(); } } diff --git a/src/main/java/com/extendedae_plus/client/ClientProxy.java b/src/main/java/com/extendedae_plus/client/ClientRegistrar.java similarity index 83% rename from src/main/java/com/extendedae_plus/client/ClientProxy.java rename to src/main/java/com/extendedae_plus/client/ClientRegistrar.java index 8b7fb46..4da808b 100644 --- a/src/main/java/com/extendedae_plus/client/ClientProxy.java +++ b/src/main/java/com/extendedae_plus/client/ClientRegistrar.java @@ -1,7 +1,10 @@ package com.extendedae_plus.client; import appeng.client.render.crafting.CraftingCubeModel; +import appeng.init.client.InitScreens; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; +import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.client.render.crafting.EPlusCraftingCubeModelProvider; import com.extendedae_plus.client.screen.GlobalProviderModesScreen; import com.extendedae_plus.content.crafting.EPlusCraftingUnitType; @@ -14,8 +17,8 @@ import net.minecraftforge.fml.ModLoadingContext; /** * 客户端模型注册,将 formed 模型注册为内置模型。 */ -public final class ClientProxy { - private ClientProxy() {} +public final class ClientRegistrar { + private ClientRegistrar() {} private static boolean REGISTERED = false; @@ -54,6 +57,15 @@ public final class ClientProxy { MenuScreens.register(ModMenuTypes.NETWORK_PATTERN_CONTROLLER.get(), GlobalProviderModesScreen::new); } + /** + * 注册由 AE2 InitScreens 所需的屏幕资源映射(用于内置 JSON 屏幕注册) + */ + public static void registerInitScreens() { + InitScreens.register(ModMenuTypes.ENTITY_TICKER_MENU.get(), + EntitySpeedTickerScreen::new, + "/screens/entity_speed_ticker.json"); + } + /** * 仅客户端:在 Mods 菜单注册配置界面入口。 * 将对 Screen 的引用限制在客户端侧,避免服务端类加载。 From 4932b5e004a89ae49442183e28e6feaa96524bed Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 00:57:40 +0800 Subject: [PATCH 10/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8=E7=95=8C=E9=9D=A2=E5=B8=83?= =?UTF-8?q?=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resources/assets/ae2/screens/entity_speed_ticker.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json index 64dfc30..7654c5e 100644 --- a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json +++ b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json @@ -25,21 +25,21 @@ }, "speed": { "position": { - "top": 45, + "top": 35, "left": 88 }, "align": "CENTER" }, "energy": { "position": { - "top": 60, + "top": 50, "left": 88 }, "align": "CENTER" }, "power_ratio": { "position": { - "top": 75, + "top": 65, "left": 88 }, "align": "CENTER" @@ -47,7 +47,7 @@ , "multiplier": { "position": { - "top": 90, + "top": 80, "left": 88 }, "align": "CENTER" From 3a35dc3430ec0f237435f38bab76244365b70bce Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 01:11:09 +0800 Subject: [PATCH 11/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8=E7=95=8C=E9=9D=A2=E6=B7=BB=E5=8A=A0=E8=83=BD?= =?UTF-8?q?=E6=BA=90=E6=98=BE=E7=A4=BA=E5=8D=95=E4=BD=8D=E5=88=87=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae/screen/EntitySpeedTickerScreen.java | 5 ++- .../com/extendedae_plus/util/PowerUtils.java | 42 ------------------- 2 files changed, 4 insertions(+), 43 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java index 3bbe7e1..087c36f 100644 --- a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java +++ b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java @@ -2,8 +2,10 @@ package com.extendedae_plus.ae.screen; import appeng.client.gui.implementations.UpgradeableScreen; import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.CommonButtons; import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; import com.extendedae_plus.util.PowerUtils; +import appeng.util.Platform; import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; @@ -12,6 +14,7 @@ public class EntitySpeedTickerScreen extends Up public EntitySpeedTickerScreen( EntitySpeedTickerMenu menu, Inventory playerInventory, Component title, ScreenStyle style) { super((C) menu, playerInventory, title, style); + this.addToLeftToolbar(CommonButtons.togglePowerUnit()); } @Override @@ -34,7 +37,7 @@ public class EntitySpeedTickerScreen extends Up double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount); setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", speed)); - setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", PowerUtils.formatPower(finalPower))); + setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(finalPower, false))); setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); setTextContent("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", multiplier))); } diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java index 067af5c..3727ecb 100644 --- a/src/main/java/com/extendedae_plus/util/PowerUtils.java +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -52,20 +52,6 @@ public final class PowerUtils { return 0.5 * (1.0 - Math.pow(0.7, energyCardCount)); } - /** - * 计算最终能耗(取整,最小为 1) - * @param speedCardCount 加速卡数量 - * @param energyCardCount 能源卡数量 - * @return 最终能耗(int) - */ - public static int getFinalPowerDraw(int speedCardCount, int energyCardCount) { - double raw = getRawPower(speedCardCount); - double reduction = getReductionPercent(energyCardCount); - // 与原始实现兼容:raw * (1 - reduction) 后按 0.5 的单位转换(与 AE/FE 换算保持一致) - double adjusted = raw * (1.0 - reduction) / 2.0; - return (int) Math.max(1, Math.round(adjusted)); - } - /** * 计算最终能耗(浮点数) * @param speedCardCount 加速卡数量 @@ -88,34 +74,6 @@ public final class PowerUtils { return 1.0 - getReductionPercent(energyCardCount); } - /** - * 将能耗数字按单位缩写(K/M/G/T/P/E)格式化为更短的字符串 - * 例如 1500 -> "1.50K", 2000000 -> "2.00M" - */ - public static String formatPower(double value) { - double abs = Math.abs(value); - if (abs >= 1e18) return formatWithSuffix(value, 1e18, "E"); - if (abs >= 1e15) return formatWithSuffix(value, 1e15, "P"); - if (abs >= 1e12) return formatWithSuffix(value, 1e12, "T"); - if (abs >= 1e9) return formatWithSuffix(value, 1e9, "G"); - if (abs >= 1e6) return formatWithSuffix(value, 1e6, "M"); - if (abs >= 1e3) return formatWithSuffix(value, 1e3, "K"); - // 小于 1000 直接返回整数形式 - if (Math.floor(value) == value) { - return String.format("%d", (long) value); - } - return String.format("%.2f", value); - } - - private static String formatWithSuffix(double value, double unit, String suffix) { - double v = value / unit; - // 如果 v 是整数则不显示小数 - if (Math.abs(v - Math.round(v)) < 1e-9) { - return String.format("%d%s", Math.round(v), suffix); - } - return String.format("%.2f%s", v, suffix); - } - /** * 将剩余功耗比率格式化为百分比字符串(例如 0.9 -> "90%") */ From b470b3bd47d11d7a324f871515ccbf1bae97bd50 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 01:47:18 +0800 Subject: [PATCH 12/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/util/PowerUtils.java | 4 +- .../assets/extendedae_plus/lang/zh_cn.json | 44 ++++++++++--------- 2 files changed, 25 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java index 3727ecb..b86bef1 100644 --- a/src/main/java/com/extendedae_plus/util/PowerUtils.java +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -61,8 +61,8 @@ public final class PowerUtils { public static double getFinalPower(int speedCardCount, int energyCardCount) { double raw = getRawPower(speedCardCount); double reduction = getReductionPercent(energyCardCount); - // 返回与实际抽取值一致的浮点能耗(包含与原实现一致的 /2 单位转换) - return raw * (1.0 - reduction) / 2.0; + // 返回与实际抽取值一致的浮点能耗(在原实现基础上再除以 2,以降低能耗) + return raw * (1.0 - reduction) / 4.0; } /** diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 619b23f..1179156 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -3,9 +3,29 @@ "gui.expatternprovider.hide_slots": "隐藏槽位", "gui.expatternprovider.show_slots": "显示槽位", "gui.expatternprovider.clear_selection": "取消选择", - "block.extendedae_plus.wireless_transceiver": "无线收发器", - "item.extendedae_plus.wireless_transceiver": "无线收发器", + "gui.extendedae_plus.global.toggle_blocking": "切换阻挡模式", + "gui.extendedae_plus.global.toggle_adv_blocking": "切换高级阻挡", + "gui.extendedae_plus.global.toggle_smart_doubling": "切换智能翻倍", + "gui.extendedae_plus.global.all_on": "全部开启", + "gui.extendedae_plus.global.all_off": "全部关闭", + "itemGroup.extendedae_plus.main": "扩展AE Plus", + "item.extendedae_plus.wireless_transceiver": "无线收发器", + "item.extendedae_plus.4x_crafting_accelerator": "4x并行处理单元", + "item.extendedae_plus.16x_crafting_accelerator": "16x并行处理单元", + "item.extendedae_plus.64x_crafting_accelerator": "64x并行处理单元", + "item.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元", + "item.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元", + "item.extendedae_plus.network_pattern_controller": "样板供应器状态控制器", + + "block.extendedae_plus.wireless_transceiver": "无线收发器", + "block.extendedae_plus.4x_crafting_accelerator": "4x并行处理单元", + "block.extendedae_plus.16x_crafting_accelerator": "16x并行处理单元", + "block.extendedae_plus.64x_crafting_accelerator": "64x并行处理单元", + "block.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元", + "block.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元", + "block.extendedae_plus.network_pattern_controller": "样板供应器状态控制器", + "extendedae_plus.upload_to_matrix": "上传到装配矩阵", "extendedae_plus.upload_to_matrix.success": "样板已上传到装配矩阵", "extendedae_plus.upload_to_matrix.fail_not_crafting": "仅支持上传合成样板,处理样板将被忽略", @@ -16,18 +36,6 @@ "extendedae_plus.screen.cn_name": "中文名", "extendedae_plus.button.choose_provider":"上传样板", "extendedae_plus.pattern.hovertext.player": "由 %s 编码", - - "block.extendedae_plus.4x_crafting_accelerator": "4x并行处理单元", - "block.extendedae_plus.16x_crafting_accelerator": "16x并行处理单元", - "block.extendedae_plus.64x_crafting_accelerator": "64x并行处理单元", - "block.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元", - "block.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元", - - "item.extendedae_plus.4x_crafting_accelerator": "4x并行处理单元", - "item.extendedae_plus.16x_crafting_accelerator": "16x并行处理单元", - "item.extendedae_plus.64x_crafting_accelerator": "64x并行处理单元", - "item.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元", - "item.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元", "item.extendedae_plus.entity_speed_ticker": "实体加速器", "screen.extendedae_plus.entity_speed_ticker.energy": "能耗: %s FE/t", @@ -46,6 +54,7 @@ "extendedae_plus.tooltip.locked": "锁定状态: %s", "screen.extendedae_plus.title": "ExtendedAE Plus 配置", + "config.extendedae_plus.pageMultiplier": "扩展样板供应器槽位倍率", "config.extendedae_plus.pageMultiplier_with_range": "扩展样板供应器槽位倍率 (1-64)", "config.extendedae_plus.wirelessMaxRange": "无线最大距离", @@ -56,13 +65,6 @@ "config.extendedae_plus.state_off": "关", "config.extendedae_plus.showEncoderPatternPlayer": "显示样板编码玩家", "config.extendedae_plus.patternTerminalShowSlotsDefault": "样板终端默认显示槽位", - "block.extendedae_plus.network_pattern_controller": "样板供应器状态控制器", - "item.extendedae_plus.network_pattern_controller": "样板供应器状态控制器", - "gui.extendedae_plus.global.toggle_blocking": "切换阻挡模式", - "gui.extendedae_plus.global.toggle_adv_blocking": "切换高级阻挡", - "gui.extendedae_plus.global.toggle_smart_doubling": "切换智能翻倍", - "gui.extendedae_plus.global.all_on": "全部开启", - "gui.extendedae_plus.global.all_off": "全部关闭", "config.extendedae_plus.smartScalingMaxMultiplier": "智能倍增最大倍数", "config.extendedae_plus.smartScalingMaxMultiplier_with_range": "智能倍增最大倍数 (0为不限制)", "config.extendedae_plus.smartScalingMinBenefitFactor": "智能倍增最小收益因子 (默认 4)" From 045eac8f0e197fc30f707dfe3cd8967c5b1a45af Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 09:19:34 +0800 Subject: [PATCH 13/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8=E6=B7=BB=E5=8A=A0=E6=8E=A7=E5=88=B6=E6=8C=89?= =?UTF-8?q?=E9=92=AE=EF=BC=9B=E8=B0=83=E6=95=B4ModNetwork=E4=BD=8D?= =?UTF-8?q?=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 1 - .../ae/menu/EntitySpeedTickerMenu.java | 18 ++++++ .../ae/parts/EntitySpeedTickerPart.java | 17 ++++++ .../ae/screen/EntitySpeedTickerScreen.java | 56 +++++++++++++++++-- .../extendedae_plus/client/InputEvents.java | 4 +- .../screen/GlobalProviderModesScreen.java | 2 +- .../client/ui/ProviderSelectScreen.java | 2 +- .../{network => init}/ModNetwork.java | 9 ++- .../mixin/PickFromWirelessMixin.java | 2 +- .../ae2/client/gui/AEBaseScreenMixin.java | 2 +- .../gui/PatternEncodingTermScreenMixin.java | 2 +- .../gui/PatternProviderScreenMixin.java | 2 +- .../client/gui/GuiExPatternTerminalMixin.java | 2 +- .../CraftingMonitorOpenProviderC2SPacket.java | 1 + .../RequestProvidersListC2SPacket.java | 1 + .../network/ToggleEntityTickerC2SPacket.java | 45 +++++++++++++++ 16 files changed, 150 insertions(+), 16 deletions(-) rename src/main/java/com/extendedae_plus/{network => init}/ModNetwork.java (93%) create mode 100644 src/main/java/com/extendedae_plus/network/ToggleEntityTickerC2SPacket.java diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 62a0d6b..76f30ba 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -5,7 +5,6 @@ import com.extendedae_plus.client.ClientRegistrar; import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.*; import com.extendedae_plus.menu.locator.CuriosItemLocator; -import com.extendedae_plus.network.ModNetwork; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index 270131d..b8269dc 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -1,6 +1,7 @@ package com.extendedae_plus.ae.menu; import appeng.core.definitions.AEItems; +import appeng.menu.guisync.GuiSync; import appeng.menu.implementations.UpgradeableMenu; import appeng.menu.slot.OptionalFakeSlot; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; @@ -22,11 +23,28 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu extends UpgradeableScreen { + private boolean eap$entitySpeedTickerEnabled = false; + private SettingToggleButton eap$entitySpeedTickerToggle; public EntitySpeedTickerScreen( EntitySpeedTickerMenu menu, Inventory playerInventory, Component title, ScreenStyle style) { super((C) menu, playerInventory, title, style); this.addToLeftToolbar(CommonButtons.togglePowerUnit()); + + try{ + this.eap$entitySpeedTickerEnabled = menu.getAccelerateEnabled(); + }catch (Exception ignored){} + + // 使用 SettingToggleButton 的外观(原版图标),但自定义悬停描述为“智能阻挡” + // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 + eap$entitySpeedTickerToggle = new SettingToggleButton<>( + Settings.BLOCKING_MODE, + this.eap$entitySpeedTickerEnabled ? YesNo.YES : YesNo.NO, + (btn, backwards) -> { + // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 + ModNetwork.CHANNEL.sendToServer(new ToggleEntityTickerC2SPacket()); + } + ) { + @Override + public List getTooltipMessage() { + boolean enabled = eap$entitySpeedTickerEnabled; + var title = Component.literal("实体加速"); + var stateLine = enabled + ? Component.literal("已启用: 将加速目标方块实体的tick") + : Component.literal("已关闭: 不会对目标方块实体进行加速"); + return List.of(title, stateLine); + } + }; + // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 + eap$entitySpeedTickerToggle.set(this.eap$entitySpeedTickerEnabled ? YesNo.YES : YesNo.NO); + + this.addToLeftToolbar(eap$entitySpeedTickerToggle); } @Override - protected void updateBeforeRender(){ + protected void updateBeforeRender() { super.updateBeforeRender(); + + if (this.eap$entitySpeedTickerToggle != null) { + boolean desired = this.eap$entitySpeedTickerEnabled; + if (this.menu != null) { + desired = this.menu.getAccelerateEnabled(); + } + + this.eap$entitySpeedTickerEnabled = desired; + this.eap$entitySpeedTickerToggle.set(desired ? YesNo.YES : YesNo.NO); + } textData(); } - public void refreshGui(){ + public void refreshGui() { textData(); } diff --git a/src/main/java/com/extendedae_plus/client/InputEvents.java b/src/main/java/com/extendedae_plus/client/InputEvents.java index 8af06d1..44e9f85 100644 --- a/src/main/java/com/extendedae_plus/client/InputEvents.java +++ b/src/main/java/com/extendedae_plus/client/InputEvents.java @@ -4,16 +4,14 @@ import appeng.api.stacks.GenericStack; import appeng.client.gui.me.common.MEStorageScreen; import appeng.integration.modules.jei.GenericEntryStackHelper; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.integration.jei.JeiRuntimeProxy; import com.extendedae_plus.mixin.ae2.accessor.MEStorageScreenAccessor; -import com.extendedae_plus.network.ModNetwork; import com.extendedae_plus.network.OpenCraftFromJeiC2SPacket; import com.extendedae_plus.network.PullFromJeiOrCraftC2SPacket; -import mezz.jei.api.constants.VanillaTypes; import mezz.jei.api.ingredients.ITypedIngredient; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; -import net.minecraft.world.item.ItemStack; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ScreenEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; diff --git a/src/main/java/com/extendedae_plus/client/screen/GlobalProviderModesScreen.java b/src/main/java/com/extendedae_plus/client/screen/GlobalProviderModesScreen.java index c70a53f..49c36a8 100644 --- a/src/main/java/com/extendedae_plus/client/screen/GlobalProviderModesScreen.java +++ b/src/main/java/com/extendedae_plus/client/screen/GlobalProviderModesScreen.java @@ -1,8 +1,8 @@ package com.extendedae_plus.client.screen; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.menu.NetworkPatternControllerMenu; import com.extendedae_plus.network.GlobalToggleProviderModesC2SPacket; -import com.extendedae_plus.network.ModNetwork; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.network.chat.Component; diff --git a/src/main/java/com/extendedae_plus/client/ui/ProviderSelectScreen.java b/src/main/java/com/extendedae_plus/client/ui/ProviderSelectScreen.java index e817f2a..1984717 100644 --- a/src/main/java/com/extendedae_plus/client/ui/ProviderSelectScreen.java +++ b/src/main/java/com/extendedae_plus/client/ui/ProviderSelectScreen.java @@ -1,6 +1,6 @@ package com.extendedae_plus.client.ui; -import com.extendedae_plus.network.ModNetwork; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.network.UploadEncodedPatternToProviderC2SPacket; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.Button; diff --git a/src/main/java/com/extendedae_plus/network/ModNetwork.java b/src/main/java/com/extendedae_plus/init/ModNetwork.java similarity index 93% rename from src/main/java/com/extendedae_plus/network/ModNetwork.java rename to src/main/java/com/extendedae_plus/init/ModNetwork.java index 78e3adb..2f4eab5 100644 --- a/src/main/java/com/extendedae_plus/network/ModNetwork.java +++ b/src/main/java/com/extendedae_plus/init/ModNetwork.java @@ -1,6 +1,7 @@ -package com.extendedae_plus.network; +package com.extendedae_plus.init; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.network.*; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkDirection; import net.minecraftforge.network.NetworkRegistry; @@ -90,6 +91,12 @@ public class ModNetwork { .consumerNetworkThread(GlobalToggleProviderModesC2SPacket::handle) .add(); + CHANNEL.messageBuilder(ToggleEntityTickerC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER) + .encoder(ToggleEntityTickerC2SPacket::encode) + .decoder(ToggleEntityTickerC2SPacket::decode) + .consumerNetworkThread(ToggleEntityTickerC2SPacket::handle) + .add(); + CHANNEL.messageBuilder(AdvancedBlockingSyncS2CPacket.class, nextId(), NetworkDirection.PLAY_TO_CLIENT) .encoder(AdvancedBlockingSyncS2CPacket::encode) .decoder(AdvancedBlockingSyncS2CPacket::decode) diff --git a/src/main/java/com/extendedae_plus/mixin/PickFromWirelessMixin.java b/src/main/java/com/extendedae_plus/mixin/PickFromWirelessMixin.java index 56fe87f..33b6254 100644 --- a/src/main/java/com/extendedae_plus/mixin/PickFromWirelessMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/PickFromWirelessMixin.java @@ -1,6 +1,6 @@ package com.extendedae_plus.mixin; -import com.extendedae_plus.network.ModNetwork; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.network.PickFromWirelessC2SPacket; import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java index b741be3..5d089eb 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java @@ -15,9 +15,9 @@ import appeng.client.gui.style.TextAlignment; import appeng.menu.slot.AppEngSlot; import com.extendedae_plus.api.ExPatternPageAccessor; import com.extendedae_plus.content.ClientPatternHighlightStore; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.network.CraftingMonitorJumpC2SPacket; import com.extendedae_plus.network.CraftingMonitorOpenProviderC2SPacket; -import com.extendedae_plus.network.ModNetwork; import com.extendedae_plus.util.GuiUtil; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import com.mojang.logging.LogUtils; diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternEncodingTermScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternEncodingTermScreenMixin.java index 7119000..23c262f 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternEncodingTermScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternEncodingTermScreenMixin.java @@ -7,10 +7,10 @@ import appeng.client.gui.style.ScreenStyle; import appeng.client.gui.style.WidgetStyle; import appeng.client.gui.widgets.IconButton; import appeng.menu.AEBaseMenu; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.mixin.accessor.AbstractContainerScreenAccessor; import com.extendedae_plus.mixin.accessor.ScreenAccessor; import com.extendedae_plus.mixin.ae2.accessor.AEBaseScreenAccessor; -import com.extendedae_plus.network.ModNetwork; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Tooltip; import net.minecraft.client.renderer.Rect2i; diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java index 883fc2a..2fb5edd 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java @@ -10,7 +10,7 @@ import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.ExPatternButtonsAccessor; import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import com.extendedae_plus.api.PatternProviderMenuDoublingSync; -import com.extendedae_plus.network.ModNetwork; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternTerminalMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternTerminalMixin.java index e8b5402..65f01f4 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternTerminalMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternTerminalMixin.java @@ -9,8 +9,8 @@ import appeng.client.gui.widgets.AETextField; import appeng.client.gui.widgets.IconButton; import appeng.menu.AEBaseMenu; import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.mixin.extendedae.accessor.GuiExPatternTerminalAccessor; -import com.extendedae_plus.network.ModNetwork; import com.extendedae_plus.network.OpenProviderUiC2SPacket; import com.extendedae_plus.util.GuiUtil; import com.glodblock.github.extendedae.client.gui.GuiExPatternTerminal; diff --git a/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java b/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java index 6680f2f..91ddfa0 100644 --- a/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/CraftingMonitorOpenProviderC2SPacket.java @@ -11,6 +11,7 @@ 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.util.PatternProviderDataUtil; import com.glodblock.github.extendedae.util.FCClientUtil; diff --git a/src/main/java/com/extendedae_plus/network/RequestProvidersListC2SPacket.java b/src/main/java/com/extendedae_plus/network/RequestProvidersListC2SPacket.java index 88e51d6..d9a0cc3 100644 --- a/src/main/java/com/extendedae_plus/network/RequestProvidersListC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/RequestProvidersListC2SPacket.java @@ -3,6 +3,7 @@ package com.extendedae_plus.network; import appeng.helpers.patternprovider.PatternContainer; import appeng.menu.implementations.PatternAccessTermMenu; import appeng.menu.me.items.PatternEncodingTermMenu; +import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.util.ExtendedAEPatternUploadUtil; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; diff --git a/src/main/java/com/extendedae_plus/network/ToggleEntityTickerC2SPacket.java b/src/main/java/com/extendedae_plus/network/ToggleEntityTickerC2SPacket.java new file mode 100644 index 0000000..0e4163d --- /dev/null +++ b/src/main/java/com/extendedae_plus/network/ToggleEntityTickerC2SPacket.java @@ -0,0 +1,45 @@ +package com.extendedae_plus.network; + +import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; +import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +/** + * C2S: Toggle the accelerateEnabled flag on the EntitySpeedTickerPart bound to the open menu. + */ +public class ToggleEntityTickerC2SPacket { + public ToggleEntityTickerC2SPacket() { + } + + public static void encode(ToggleEntityTickerC2SPacket msg, FriendlyByteBuf buf) { + } + + public static ToggleEntityTickerC2SPacket decode(FriendlyByteBuf buf) { + return new ToggleEntityTickerC2SPacket(); + } + + public static void handle(ToggleEntityTickerC2SPacket msg, Supplier ctxSupplier) { + var ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> { + ServerPlayer player = ctx.getSender(); + if (player == null) return; + if (!(player.containerMenu instanceof EntitySpeedTickerMenu menu)) return; + + EntitySpeedTickerPart part = menu.getHost(); + if (part == null) return; + + // 切换部件上的状态,并把新状态同步到菜单字段,随后广播以通知客户端 + boolean current = part.getAccelerateEnabled(); + boolean next = !current; + part.setAccelerateEnabled(next); + // 确保菜单上的字段也被更新,这样 @GuiSync 会把状态发回客户端 + menu.setAccelerateEnabled(next); + menu.broadcastChanges(); + }); + ctx.setPacketHandled(true); + } +} \ No newline at end of file From e697552b6b2a9d62f8983ce3612ba72a644a8e4a Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 12 Sep 2025 13:23:15 +0800 Subject: [PATCH 14/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8=E5=90=88=E6=88=90=E9=85=8D=E6=96=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../recipes/entity_speed_ticker.json | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json diff --git a/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json b/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json new file mode 100644 index 0000000..df4ee1d --- /dev/null +++ b/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json @@ -0,0 +1,21 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SZS", + "QXQ", + "SIS" + ], + "key": { + "S": { "item": "ae2:speed_card" }, + "Z": { "item": "ae2:dense_energy_cell" }, + "Q": { "item": "ae2:singularity" }, + "X": { "item": "minecraft:nether_star" }, + "I": { "item": "expatternprovider:ex_io_port" } + }, + "result": { + "item": "extendedae_plus:entity_speed_ticker", + "count": 1 + } +} + + From fb2a2a831d698dceb644b9514b3256a472e234f0 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sat, 13 Sep 2025 12:50:47 +0800 Subject: [PATCH 15/44] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=8D=A1=E6=9B=BF=E6=8D=A2=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=8D=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../com/extendedae_plus/ExtendedAEPlus.java | 3 +- .../upgrades/EntitySpeedCardItem.java | 81 +++++++++++ .../ae/menu/EntitySpeedTickerMenu.java | 30 +++-- .../ae/parts/EntitySpeedTickerPart.java | 27 ++-- .../ae/screen/EntitySpeedTickerScreen.java | 7 +- .../client/ClientRegistrar.java | 6 + .../extendedae_plus/init/ModCreativeTabs.java | 6 + .../com/extendedae_plus/init/ModItems.java | 22 ++- .../extendedae_plus/init/UpgradeCards.java | 4 +- .../com/extendedae_plus/util/PowerUtils.java | 127 ++++++++++++++---- .../assets/extendedae_plus/lang/en_us.json | 7 + .../assets/extendedae_plus/lang/zh_cn.json | 7 + .../models/item/entity_speed_card.json | 14 ++ .../models/item/entity_speed_card_x1.json | 6 + .../models/item/entity_speed_card_x16.json | 6 + .../models/item/entity_speed_card_x2.json | 6 + .../models/item/entity_speed_card_x4.json | 6 + .../models/item/entity_speed_card_x8.json | 6 + .../textures/item/entity_speed_card_x16.png | Bin 0 -> 2323 bytes .../textures/item/entity_speed_card_x2.png | Bin 0 -> 2084 bytes .../textures/item/entity_speed_card_x4.png | Bin 0 -> 2326 bytes .../textures/item/entity_speed_card_x8.png | Bin 0 -> 2307 bytes 23 files changed, 312 insertions(+), 61 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/ae/definitions/upgrades/EntitySpeedCardItem.java create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card.json create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x16.json create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x2.json create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x4.json create mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x8.json create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png diff --git a/gradle.properties b/gradle.properties index d471976..2524cfb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.4.1 +mod_version = 1.4.1-entitySpeedTicker maven_group = com.extendedae_plus archives_name = extendedae_plus diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 76f30ba..aefcb30 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -32,8 +32,7 @@ public class ExtendedAEPlus { public ExtendedAEPlus() { IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus(); - // 在客户端尽早注册内置模型,保证首次资源加载前映射已建立(仿照 AE2 的 AppEngClient 构造期注册) - DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientRegistrar::initBuiltInModels); + // 客户端的内置模型注册将在客户端事件阶段执行(见 ClientModEvents),不要在构造器中提前执行 // 注册mod初始化事件 modEventBus.addListener(this::commonSetup); diff --git a/src/main/java/com/extendedae_plus/ae/definitions/upgrades/EntitySpeedCardItem.java b/src/main/java/com/extendedae_plus/ae/definitions/upgrades/EntitySpeedCardItem.java new file mode 100644 index 0000000..cc97d98 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/definitions/upgrades/EntitySpeedCardItem.java @@ -0,0 +1,81 @@ +package com.extendedae_plus.ae.definitions.upgrades; + +import appeng.items.materials.UpgradeCardItem; +import com.extendedae_plus.init.ModItems; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * 单一的实体加速卡 Item,通过 ItemStack 的 NBT 存储 exponent(0/1/2/3)来区分等级 + */ +public class EntitySpeedCardItem extends UpgradeCardItem { + public static final String NBT_MULTIPLIER = "EAS:mult"; + + public EntitySpeedCardItem(Properties props) { + super(props); + } + + public static ItemStack withMultiplier(int multiplier) { + ItemStack s = new ItemStack(ModItems.ENTITY_SPEED_CARD.get()); + CompoundTag t = s.getOrCreateTag(); + t.putInt(NBT_MULTIPLIER, multiplier); + s.setTag(t); + return s; + } + + public static int readMultiplier(ItemStack stack) { + if (stack == null || stack.isEmpty()) return 1; + CompoundTag t = stack.getTag(); + if (t == null) return 1; + int v = t.getInt(NBT_MULTIPLIER); + return v <= 0 ? 1 : v; + } + + @Override + public @NotNull Component getName(@NotNull ItemStack stack) { + int mult = readMultiplier(stack); + String key; + switch (mult) { + case 2 -> key = "item." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.x2"; + case 4 -> key = "item." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.x4"; + case 8 -> key = "item." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.x8"; + case 16 -> key = "item." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.x16"; + default -> key = "item." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.x1"; + } + return Component.translatable(key); + } + + + public List getTooltipLines(ItemStack stack) { + int mult = readMultiplier(stack); + long cap = 1L; + switch (mult) { + case 16 -> cap = 1024L; + case 8 -> cap = 256L; + case 4 -> cap = 64L; + case 2 -> cap = 8L; + } + MutableComponent line1 = Component.translatable("tooltip." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.multiplier", "x" + mult); + MutableComponent line2 = Component.translatable("tooltip." + com.extendedae_plus.ExtendedAEPlus.MODID + ".entity_speed_card.max", cap); + return List.of(line1, line2); + } + + @OnlyIn(Dist.CLIENT) + @Override + public void appendHoverText(ItemStack stack, Level level, List lines, TooltipFlag flag) { + super.appendHoverText(stack, level, lines, flag); + // add our custom tooltip lines (multiplier and max) + lines.addAll(this.getTooltipLines(stack)); + } +} + + diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index b8269dc..6eb75e2 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -7,8 +7,10 @@ import appeng.menu.slot.OptionalFakeSlot; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.util.ConfigParsingUtils; +import com.extendedae_plus.util.PowerUtils; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.level.block.entity.BlockEntity; @@ -16,16 +18,15 @@ import net.minecraftforge.registries.ForgeRegistries; // 实体加速器菜单,负责与客户端界面同步数据 public class EntitySpeedTickerMenu extends UpgradeableMenu { - // 已安装的速度卡数量 - public int speedCardCount; + @GuiSync(716) public boolean accelerateEnabled = true; + // 已安装的实体加速卡数量(用于能耗计算) + @GuiSync(717) public int entitySpeedCardCount; // 已安装的能量卡数量 - public int energyCardCount; - // 当前生效的倍率(从配置中读取并同步) - public double multiplier = 1.0; - - @GuiSync(716) - public boolean accelerateEnabled = true; - + @GuiSync(718) public int energyCardCount; + // 当前生效的配置倍率(从配置中读取并同步) + // 当前计算出的生效速度(product of multipliers),同步给客户端用于显示 + @GuiSync(719) public int effectiveSpeed = 1; + @GuiSync(720) public double multiplier = 1.0; public boolean getAccelerateEnabled() { return this.accelerateEnabled; @@ -51,8 +52,8 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu) blockEntity.getType()); if (blockEntityTicker == null) return; - int speedCardCount = getUpgrades().getInstalledUpgrades(AEItems.SPEED_CARD); + // 使用集中定义的 CardDef 列表,支持以后添加等级或改倍率而无需修改此逻辑 int energyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD); - // 计算本次 tick 所需能量 - // - 基础消耗为 512 - // - 加速卡的数量对能耗有分段增长: - // 0: 无增长 - // 1: 翻倍 - // 2-6: 指数增长(较快) - // 7-8: 幂级数增长(极高) - // 使用工具类统一计算增长因子与原始功耗,并从网络中抽取对应能量 - double requiredPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); + // 使用已注册的单一 Item 计算已安装卡数量(总计,用于能耗计算) + int entitySpeedCardCount = getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get()); + + // 使用工具方法从槽位直接计算乘积并应用 cap(最多 8 张卡) + long product = PowerUtils.computeProductWithCapFromStacks(this.getUpgrades(), 8); + + // 如果没有任何实体加速卡,则不进行加速且不消耗额外能量(只保留部件的被动功耗) + if (entitySpeedCardCount <= 0) return; + + // 计算本次 tick 所需能量:使用工具类根据 product 计算最终能耗 + double requiredPower = PowerUtils.computeFinalPowerForProduct(product, energyCardCount); + + int speed = (int) product; double multiplier = 1.0; for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(ModConfigs.EntitySpeedTickerMultipliers.get())) { @@ -241,7 +246,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka if (extractedPower < requiredPower) return; // 计算加速倍数:基于 2 的次方,并把 8 张映射到最大 1024x(2^10) - int speed = PowerUtils.getSpeedMultiplier(speedCardCount); + // 已由 product 计算得到 speed;上面已在没有卡时提前返回 // 执行 tick 操作 for (int i = 0; i < speed - 1; i++) { diff --git a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java index e57748d..7a1f390 100644 --- a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java +++ b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java @@ -76,15 +76,14 @@ public class EntitySpeedTickerScreen extends Up } private void textData() { - int speedCardCount = getMenu().speedCardCount; int energyCardCount = getMenu().energyCardCount; double multiplier = getMenu().multiplier; + int effectiveSpeed = getMenu().effectiveSpeed; - double finalPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); - int speed = PowerUtils.getSpeedMultiplier(speedCardCount); + double finalPower = PowerUtils.computeFinalPowerForProduct(effectiveSpeed, energyCardCount); double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount); - setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", speed)); + setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", effectiveSpeed)); setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(finalPower, false))); setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); setTextContent("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", multiplier))); diff --git a/src/main/java/com/extendedae_plus/client/ClientRegistrar.java b/src/main/java/com/extendedae_plus/client/ClientRegistrar.java index 4da808b..61a24bc 100644 --- a/src/main/java/com/extendedae_plus/client/ClientRegistrar.java +++ b/src/main/java/com/extendedae_plus/client/ClientRegistrar.java @@ -3,14 +3,17 @@ package com.extendedae_plus.client; import appeng.client.render.crafting.CraftingCubeModel; import appeng.init.client.InitScreens; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; import com.extendedae_plus.client.render.crafting.EPlusCraftingCubeModelProvider; import com.extendedae_plus.client.screen.GlobalProviderModesScreen; import com.extendedae_plus.content.crafting.EPlusCraftingUnitType; import com.extendedae_plus.hooks.BuiltInModelHooks; +import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModMenuTypes; import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.renderer.item.ItemProperties; import net.minecraftforge.client.ConfigScreenHandler; import net.minecraftforge.fml.ModLoadingContext; @@ -28,6 +31,9 @@ public final class ClientRegistrar { public static void initBuiltInModels() { if (REGISTERED) return; REGISTERED = true; + // 注册 Item property,用于根据 ItemStack 的 NBT exponent 切换模型 + ItemProperties.register(ModItems.ENTITY_SPEED_CARD.get(), ExtendedAEPlus.id("mult"), + (stack, world, entity, seed) -> (float) EntitySpeedCardItem.readMultiplier(stack)); // 注册四种形成态模型为内置模型 BuiltInModelHooks.addBuiltInModel( ExtendedAEPlus.id("block/crafting/4x_accelerator_formed_v2"), diff --git a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java index d44b721..68bdba4 100644 --- a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java +++ b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java @@ -27,6 +27,12 @@ public final class ModCreativeTabs { output.accept(ModItems.ACCELERATOR_256x.get()); output.accept(ModItems.ACCELERATOR_1024x.get()); output.accept(ModItems.ENTITY_TICKER_PART_ITEM.get()); + + // 放入四个预设的 stacks(x2,x4,x8,x16),使用 ModItems 工厂创建 + output.accept(ModItems.createEntitySpeedCardStack(2)); + output.accept(ModItems.createEntitySpeedCardStack(4)); + output.accept(ModItems.createEntitySpeedCardStack(8)); + output.accept(ModItems.createEntitySpeedCardStack(16)); }) .build()); } diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index c3ee08c..7341c99 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -4,6 +4,7 @@ import appeng.api.parts.IPart; import appeng.api.parts.PartModels; import appeng.items.parts.PartModelsHelper; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; @@ -52,9 +53,17 @@ public final class ModItems { () -> new BlockItem(ModBlocks.ACCELERATOR_1024x.get(), new Item.Properties()) ); - public static final RegistryObject ENTITY_TICKER_PART_ITEM = - ITEMS.register("entity_speed_ticker", - () -> new EntitySpeedTickerPartItem(new Item.Properties())); + public static final RegistryObject ENTITY_TICKER_PART_ITEM = ITEMS.register( + "entity_speed_ticker", + () -> new EntitySpeedTickerPartItem(new Item.Properties()) + ); + + // AE Upgrade Cards: 实体加速卡(四个等级:x2,x4,x8,x16) + // 单一实体加速卡 Item(不同等级由 ItemStack.nbt 存储) + public static final RegistryObject ENTITY_SPEED_CARD = ITEMS.register( + "entity_speed_card", + () -> new EntitySpeedCardItem(new Item.Properties()) + ); /** * 为 PartItem 注册 AE2 部件模型。 @@ -67,4 +76,11 @@ public final class ModItems { ) ); } + + /** + * 工厂:创建带 multiplier 的实体加速卡 ItemStack(2/4/8/16) + */ + public static net.minecraft.world.item.ItemStack createEntitySpeedCardStack(int multiplier) { + return EntitySpeedCardItem.withMultiplier(multiplier); + } } diff --git a/src/main/java/com/extendedae_plus/init/UpgradeCards.java b/src/main/java/com/extendedae_plus/init/UpgradeCards.java index 8c7dd5d..ddd73d4 100644 --- a/src/main/java/com/extendedae_plus/init/UpgradeCards.java +++ b/src/main/java/com/extendedae_plus/init/UpgradeCards.java @@ -8,8 +8,10 @@ import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; public class UpgradeCards { public UpgradeCards(final FMLCommonSetupEvent event) { event.enqueueWork(() -> { - Upgrades.add(AEItems.SPEED_CARD, ModItems.ENTITY_TICKER_PART_ITEM.get(), 8, "group.entity_ticker.name"); + // 现有:把 Entity Ticker 的部件注册为处理 SPEED/ENERGY 卡的宿主 Upgrades.add(AEItems.ENERGY_CARD, ModItems.ENTITY_TICKER_PART_ITEM.get(), 8, "group.entity_ticker.name"); + // 使用单一的 UpgradeCard Item 作为注册键,总共允许安装 4 张(不同等级由 ItemStack NBT 区分) + Upgrades.add(ModItems.ENTITY_SPEED_CARD.get(), ModItems.ENTITY_TICKER_PART_ITEM.get(), 4, "group.entity_ticker.name"); }); } } \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java index b86bef1..18219e0 100644 --- a/src/main/java/com/extendedae_plus/util/PowerUtils.java +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -1,5 +1,6 @@ package com.extendedae_plus.util; +import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.config.ModConfigs; /** @@ -7,23 +8,111 @@ import com.extendedae_plus.config.ModConfigs; */ public final class PowerUtils { private PowerUtils() {} - + // ---- 重构后的 API ---- /** - * 计算加速卡数量对应的加速倍率(返回 2 的幂次方) - * 0 张卡 = 1x,8 张卡 = 1024x + * 将 card multipliers(按插槽序)计算乘积并应用 cap 规则(见 capForHighestMultiplier) + * @param multipliers iterable of per-card multipliers + * @param maxCards 最多计入的卡数 + * @return 被 cap 约束后的乘积 */ - public static int getSpeedMultiplier(int speedCardCount) { - if (speedCardCount <= 0) return 1; - // 线性映射 0~8 -> 0~10,最大 2^10=1024 - int exponent = (int) Math.round((10.0 / 8.0) * speedCardCount); - exponent = Math.min(exponent, 10); - return (int) Math.pow(2, exponent); + public static long computeProductWithCap(Iterable multipliers, int maxCards) { + long product = 1L; + int considered = 0; + int highest = 1; + for (Integer m : multipliers) { + if (m == null) continue; + if (considered >= maxCards) break; + int mult = m.intValue(); + if (mult <= 0) mult = 1; + product *= mult; + highest = Math.max(highest, mult); + considered++; + } + long cap = capForHighestMultiplier(highest); + return Math.min(product, cap); } /** - * 计算加速卡数量对应的能耗增长因子 - * 0: 1x,1: 2x,2-6: 2^(2*count),7-8: 2^(3*count) + * 根据最高单卡 multiplier 返回 cap 值 */ + public static long capForHighestMultiplier(int highestMultiplier) { + if (highestMultiplier >= 16) return 1024L; + if (highestMultiplier >= 8) return 256L; + if (highestMultiplier >= 4) return 64L; + if (highestMultiplier >= 2) return 8L; + return 1L; + } + + /** + * 从菜单对象读取前 maxCards 个加速卡的 multiplier 并计算 product with cap + */ + public static long computeProductWithCapFromMenu(appeng.menu.implementations.UpgradeableMenu menu, int maxCards) { + java.util.List list = new java.util.ArrayList<>(); + int considered = 0; + for (var stack : menu.getUpgrades()) { + if (considered >= maxCards) break; + if (stack != null && !stack.isEmpty() && stack.getItem() instanceof EntitySpeedCardItem) { + int multVal = EntitySpeedCardItem.readMultiplier(stack); + int count = Math.min(stack.getCount(), maxCards - considered); + for (int i = 0; i < count; i++) { + list.add(multVal); + considered++; + if (considered >= maxCards) break; + } + } + } + return computeProductWithCap(list, maxCards); + } + + /** + * 从一组 ItemStack(升级槽)直接计算 product with cap(最多 maxCards) + */ + public static long computeProductWithCapFromStacks(Iterable stacks, int maxCards) { + java.util.List list = new java.util.ArrayList<>(); + int considered = 0; + for (var stack : stacks) { + if (considered >= maxCards) break; + if (stack != null && !stack.isEmpty() && stack.getItem() instanceof EntitySpeedCardItem) { + int multVal = EntitySpeedCardItem.readMultiplier(stack); + int count = Math.min(stack.getCount(), maxCards - considered); + for (int i = 0; i < count; i++) { + list.add(multVal); + considered++; + if (considered >= maxCards) break; + } + } + } + return computeProductWithCap(list, maxCards); + } + + /** + * 计算最终消耗:把 product 转换为等效卡数(log2)并调用 getFinalPower + */ + public static double computeFinalPowerForProduct(long product, int energyCardCount) { + if (product <= 1L) return 0.0; + double base = ModConfigs.EntitySpeedTickerCost.get(); + + // 计算以2为底的对数(用于分档与公式) + double log2 = Math.log(product) / Math.log(2.0); + + // 分档:product==2 为一档;4..256 为中档;512..1024 为高档 + double raw; + if (product == 2L) { + // 轻量档:线性小幅增长 + raw = base * 4; + } else if (product <= 256L) { + // 中档:增长放缓(使用 1.5 * log2) + raw = base * Math.pow(2.0, 1.5 * log2) * 2; + } else { + // 高档:增长较快(使用 2.5 * log2) + raw = base * Math.pow(2.0, 2.5 * log2); + } + + double reduction = getReductionPercent(energyCardCount); + return raw * (1.0 - reduction) / 8.0; + } + + /* ----------------- legacy helpers (restored) ----------------- */ public static double getGrowthFactor(int speedCardCount) { if (speedCardCount <= 0) return 1.0; if (speedCardCount == 1) return 2.0; @@ -31,20 +120,11 @@ public final class PowerUtils { return Math.pow(2.0, 3.0 * speedCardCount); } - /** - * 计算加速卡数量对应的原始能耗(未减免) - * @param speedCardCount 加速卡数量 - * @return 原始能耗 - */ public static double getRawPower(int speedCardCount) { double base = ModConfigs.EntitySpeedTickerCost.get(); return base * getGrowthFactor(speedCardCount); } - /** - * 计算能源卡数量对应的能耗减免百分比 - * 0: 0%,1: 10%,8: 50%,2-7: 0.5*(1-0.7^n) - */ public static double getReductionPercent(int energyCardCount) { if (energyCardCount <= 0) return 0.0; if (energyCardCount == 1) return 0.1; @@ -52,16 +132,9 @@ public final class PowerUtils { return 0.5 * (1.0 - Math.pow(0.7, energyCardCount)); } - /** - * 计算最终能耗(浮点数) - * @param speedCardCount 加速卡数量 - * @param energyCardCount 能源卡数量 - * @return 最终能耗(double) - */ public static double getFinalPower(int speedCardCount, int energyCardCount) { double raw = getRawPower(speedCardCount); double reduction = getReductionPercent(energyCardCount); - // 返回与实际抽取值一致的浮点能耗(在原实现基础上再除以 2,以降低能耗) return raw * (1.0 - reduction) / 4.0; } diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 768e2f4..7dde8f6 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -17,6 +17,13 @@ "item.extendedae_plus.256x_crafting_accelerator": "256x Crafting Accelerator", "item.extendedae_plus.1024x_crafting_accelerator": "1024x Crafting Accelerator", "item.extendedae_plus.network_pattern_controller": "Pattern Supplier State Controller", + "item.extendedae_plus.entity_speed_card": "Entity Acceleration Card", + "item.extendedae_plus.entity_speed_card.x2": "Entity Acceleration Card (x2)", + "item.extendedae_plus.entity_speed_card.x4": "Entity Acceleration Card (x4)", + "item.extendedae_plus.entity_speed_card.x8": "Entity Acceleration Card (x8)", + "item.extendedae_plus.entity_speed_card.x16": "Entity Acceleration Card (x16)", + "tooltip.extendedae_plus.entity_speed_card.multiplier": "Multiplier: %s", + "tooltip.extendedae_plus.entity_speed_card.max": "Max effective: %s x", "block.extendedae_plus.wireless_transceiver": "Wireless Transceiver", "block.extendedae_plus.4x_crafting_accelerator": "4x Crafting Accelerator", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 1179156..7126a2c 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -17,6 +17,13 @@ "item.extendedae_plus.256x_crafting_accelerator": "256x并行处理单元", "item.extendedae_plus.1024x_crafting_accelerator": "1024x并行处理单元", "item.extendedae_plus.network_pattern_controller": "样板供应器状态控制器", + "item.extendedae_plus.entity_speed_card": "实体加速卡", + "item.extendedae_plus.entity_speed_card.x2": "实体加速卡 (x2)", + "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", + "item.extendedae_plus.entity_speed_card.x8": "实体加速卡 (x8)", + "item.extendedae_plus.entity_speed_card.x16": "实体加速卡 (x16)", + "tooltip.extendedae_plus.entity_speed_card.multiplier": "乘数: %s", + "tooltip.extendedae_plus.entity_speed_card.max": "最大生效: %s 倍", "block.extendedae_plus.wireless_transceiver": "无线收发器", "block.extendedae_plus.4x_crafting_accelerator": "4x并行处理单元", diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card.json new file mode 100644 index 0000000..b33694f --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card.json @@ -0,0 +1,14 @@ +{ + "parent": "item/generated", + "overrides": [ + { "predicate": { "extendedae_plus:mult": 2.0 }, "model": "extendedae_plus:item/entity_speed_card_x2" }, + { "predicate": { "extendedae_plus:mult": 4.0 }, "model": "extendedae_plus:item/entity_speed_card_x4" }, + { "predicate": { "extendedae_plus:mult": 8.0 }, "model": "extendedae_plus:item/entity_speed_card_x8" }, + { "predicate": { "extendedae_plus:mult": 16.0 }, "model": "extendedae_plus:item/entity_speed_card_x16" } + ], + "textures": { + "layer0": "extendedae_plus:item/entity_speed_card_x2" + } +} + + diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json new file mode 100644 index 0000000..1107187 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { "layer0": "extendedae_plus:item/entity_speed_card_x2" } +} + + diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x16.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x16.json new file mode 100644 index 0000000..b1cd950 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x16.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { "layer0": "extendedae_plus:item/entity_speed_card_x16" } +} + + diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x2.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x2.json new file mode 100644 index 0000000..1107187 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x2.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { "layer0": "extendedae_plus:item/entity_speed_card_x2" } +} + + diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x4.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x4.json new file mode 100644 index 0000000..dc0dfcf --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x4.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { "layer0": "extendedae_plus:item/entity_speed_card_x4" } +} + + diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x8.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x8.json new file mode 100644 index 0000000..0b75b61 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x8.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { "layer0": "extendedae_plus:item/entity_speed_card_x8" } +} + + diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png new file mode 100644 index 0000000000000000000000000000000000000000..74e75d30731dd8fca0610ffbcee9fab9a3eae780 GIT binary patch literal 2323 zcmb_e4Qvx-7`_c~g8>-~WJ4I2TZn+W-cNh&-9g93TDCGew=vidG+yt%u4QenTyJZ) ziQ)n%;3T>Xlf>;hz)B(!eJ~MW8_g)NjOJ=Nuv6FUx zHgLIfs}(S%I=@(~E*Cio8=rxW3-OS^3seCOc|E=WA2MTMULIa+!vuzgA!@l9%hCd( zrS<|eTUG$d=_p(zNg6eAIuq+K8TD*BN|Q80kTgM2IK}Z4$&)M^`C%}eB02dY%fv`9 zcxT33s_N$nA{Y$nf_j~-lo1riaT*6r;}C%ds(h*t!hM0XE(Qw-h>F{Q86f<=G7OEDkfz4vZV9q+XTjDu};~3V+;DX*r;}UHUaL!55I4J@nFtH}a z=>%Q#EwWglbyl0->2gUHA;-T_4GbwVdQrpykW9FqF&J?{APuD~hz0-_vsiAqA?K0z& zNRO07bP2vP09Q@|d-7x+&zGGl|C`J`Z`S{p456);oem@JHDCByx3v{EGCTwqZ0$0- zRlu9*W&?b%P72&gT84gVLXg-rnWCKS3FChfNlIT??st1899ze@*Qn%FCA^+yT&(Y3ws4&<4V_L$9$>lYi;chwA^ zv$gP$b+W_$wUwCJe`eF|mh&rXHlM9Zjhp`J+`Rdp#raQPOqiEgGjN`_N5QB;NOJNp z%hah0Qk!i0j+Vxleb*+&SG5}3e;)I~jtM2ltebYJ4Z~}f+Ny7iTlnU|<8>pDzOTpS z4zF7=Ra(8Hzk^w_YsR^)XO5OPT%gi#rLRz(gL8hMH(B5R1$*lzgYd|_#J=(MF&lI5 zjc^kvbrZENCO zD*u!O>`~JH*d9FPN>TVBV nm9ka+2DGh9&g3ryJ96Gwp+Wk&la0C-?Dka%eDUi@gpR& literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png new file mode 100644 index 0000000000000000000000000000000000000000..950d6235b841728e91ca61bca4531f8c5df3cc3f GIT binary patch literal 2084 zcmbVN3s4kg9A9uS#4r-y8ZK*MOzz(9agV*#1BpYqkpsdTgkG|@``xi|cYEwE-T^6M zI;E*OI>n&Yh=!trrgb{vW0Wa;jYV4ds4T{GvOFH!lD6>+bc5xGZx}y;97mG!O##yDK}%8svufyD?qbE z37{r|!a0)EqDB*8q#Z^>8a)-&l3Kln)M_XSr%Vh*G9-v^hzQ#>ZqyfK^1v zE{g8HN)_~3Mzsb)k3KV3@baQxPVKh=SXc#^F|}$qN#k0BozyaVnxPEOk~Bk-y-=IT z3(l(kP!mq2*-2PkEu*FHfx@2QS%rNlnCBR$D0x^Iu;5``K;!eeFf@`zCQEdS5)_8+ z(n2n5Hpc3e71qlEtHq4LmsHbqAbLemmKsJW~o;atGb~-2n5Bd7o@+AR&Xso+G ztLln}j5^8z3_P#HDLrq(O|%Z+4vIG6BWW*PQ}kkAkzhN_t56j+|Rts z&VR7=M=NEor~cLlY{vg%J)9Pb}Xv# z_0G!$_{g@#tkI*}GMf|H8;SP3{niOe!sCwA=GwZIbM7Kj-e7`_^&j|K=XDeQo(YaK zTdWmVUrf5a@cM%9|2p);Eh{@l8nremZfW$4SaiwNp$U8AXY42%gc|irw+Oi(n%BI0 zrDqrt`*-`4r|$$CZY)p^XP=Z$zd)pRB%j@N{-suHI^NTLE+5%4EvAV;;+HB3n;uIZ zdv2Eh<-*TWtjA_18rEMCPrY*B%wyJl5q`_`WhzF#||r6~DTT+2H)cEpl1O)Y^+jMh*M6zJB$=qFHUb$8P*&#e|IL72`(QPj_DH8vZ;h|9GqB zWW6`BI=yb{-FbE1uFbLIn=bGRw_0vqiuP>War8HA$WHf&3!8Eb>$7L4G}P=N{*3x+ zdtKMQoXqvt8e(26X>4i^^6~kn_p@id$R56T<)v*c3jyE6BnvU263wHU- z_oAmPus!wjWW^{Uokx}Kb;&n_y3Tm~V*QO8f4$4!J#i0Gdh}TH^gG96CbvD2J!$i& z7nX0|w|w~yOTMRZ=<2gw5}kXA8b1bIq@2Bedvy1p&$pRweG^pw$F13UmYvU)F8&AH CZrfJ? literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png new file mode 100644 index 0000000000000000000000000000000000000000..1c440cc5d52c9a6d175d3c68e1021627a4fed8a4 GIT binary patch literal 2326 zcmb_e2}~4M7#{0U14|Do#AY) zhKk0cghhy8V#Z$8fmSj9(}VcTeMy=-DGxV-hA)- zzyJTgd2g26r)9*(439w&BsSA($%g0WwWDto{2$eMPk^U>e(Nj+LHfsQM+EZmrwIrW zwbtXvQFCllc~SQ21W9%RU5VEZ(Fij6l@h-o<^vUVf;^AUj9uNm4?{hY8Jo%2NSi+m zxINag0GM7j%^{ZMi=2eL@-jNPgogxPpbBV-x4@_HC1xzh%foAJn845=M9nv2DOx}@ z$7V;<krfVlu(^u#fTEYPf$8i%P9zy#4yfZ7$^t^mqY>-059;V3dB-jtlurG zvf`E>K^=a4UjSHJn=KsUp<2A&a0o?BFM?@=3i432;wbe4A{!`jVL$}wMNsA#EgL_d z765`O2OP3o(A_C}w`7zy>KJtVOpi~Ji|0i6GNr#$e7mk4NGuz?dX~G&vxDC0$>1#J2^e1WW1tLlm@O;d zfiId+(34eDB|%05+VmX$?X_JY?VYOKtw!?(8Mx&lHktEQQOn2%%rFWSTE;Teyv)yKV z7U`j~h;G4`2jI#{V9%b+)A_PX<$sfT;LZB~k|DJ9vddw_gXRl9>#?@NMh1uAf~{SK zw+eU@-fVym)+qqDl6U%ipNb&8k~1wS4)*<;>e{S$A)#SW#?}1o=DO9{qX(gJaeb3d zSf|FvN5zkewo^%Q&rQ@NAFAKD;Aq9c#Xk%iap1rPYH)l~``q@1QD^6^`Y8b&QPFy) z@yvH)+w5~D&Kq%at?Aa@wuP;2Z@2z6qZ~bJ$mnyhtutbZZe7}Irz5K>drzs&iTr%m z_5r!4+85ohe`Mc1KN2}yJGi!K0-+lG1h)c^5 z`|QhW3L`sC3>|c0@#dN5R$XZVSC7xy(Y`ZrN5zo2%6kjO{8~3K&&nX~h^p*k6Y#Q* z+_D=*ms*)p{k_H0lnj@^19B1*Hf)SJl)7ol<(sM7_kR!{ zoyo`5pZf6bwey!IA=SrMj%zhF_qE4XSR3>ER5olp*<}4P>jKq_aQb%*uBx2SxbdsT zPgcLXZF}d1lY5%im!s(VBhhU`_nqsPIP*YNYQ~E3^cJCiY{rsdQ}3L=*fO^|`gBcA wTKu9G?#SO272=?Xkv7|%R literal 0 HcmV?d00001 diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png new file mode 100644 index 0000000000000000000000000000000000000000..1b51f61e79ea7abcbfa069b2dd18277a57b45027 GIT binary patch literal 2307 zcmb_e32f6=7&f#kv|A6Y92E@VnvKE0@sZfE4WX2VBZ3s#hEZUYIrd8vn%HUVlD3>< z8ilffC|Ad^acW~oNE_0`1}n$9a%hE>t$+lG!nmi62@ryb!JgAJD~wBMksRC4-~0aW z|NqbLdEvO+k;zFtk`M$*c8s#;!*iN(bWVW(y>C7c;VCgVYNCc9FQ*$v2W0iy32nq8h0Za8qy|i)th#}zJP?Fv1R0!F9u%b#prdY3>{D#m^<8@~)F<1p35=6;26KSd zH>xrO3MzA5Qe}z6%UISBba1%<2?9VD(ei*_(S&jv7U31(wJ}U!Xau5{*syFPAX?}g zhvujufbu2^mq?OEt-Q&~xvi|38;H^*%@8C_P!vw_0!0cWhem%G3>T6;LcV=OG#I?I zVP0Ji3Iq`jhfQI#NevYf6wmVp2TkJ;fom0tE|%kp)~AiZ4m2s`3+g^qK@CRHt(NIF z3`%XyArOqwDq6Houwq2H7$hhYY2*|E%2Es$EDQM~!DWd6eh>hPu0bpn!v?*ou4-QO z3DmL24+Vg=bvk1)9;+n~h=tJf;nQIn(Ske{t+^_KfXD}$S{9PP@aa%yA0wNfkP`x; zu7+Hy>Tm1RxHics&6*gr-vpl`t6{Bwy9vN9>cEB>UBgKZr&$+C3k)Yv>;RGzNU{~` zRAry1qCJ$yDYJ{D1ez8o>qAiJ8ClfDXM$x(@Tj4H2ov@N#9}}Mm0}Eyl~Kr1{b~pX zhU&}_6;7w%P&8dsB;c^yFqpH+=aU5qm?<+&u{c9}Se)c77TnFS3~muA4<`YU<~Y7> zzFn2djLsVKTU{=z66E+ds?6~`!>~Ngu{4jHX~@QzB`YpcvXuoE$>Ju(Hny=LAAHe7 ze|uI#l?)jzlpC8)mjOARg1T$>qRM0&I= zl2=rU0bDr=?8TFLK3}$~{BJUkyjlNWGK8^SwmOV>)O?X=?bcS<$jA^}u#L;uRsnBf zn+;H4okDOcIneF?Z3O9v!QFQZ}3iPLLNU+8P4@NT1*IW`~PP(8fk zdr9+_<&N8UU-XZEA4yA5q zN}#5p@U_a8Klh*8ee~v_)ay(Ar!H}$6Iu>*?b(t?SEspK=8;aM`Uecz5X^A?Ts!mj z&`C81QsU>XxHfX|&0c*c;kVvSpZfi0~ zGZ(*pCGo@YN#2cze;r$Tc>ca)mzgnn#lP*x@;7}mHrOvtudO*V>%FF#DdSxeKP{^7 zKW6)EXAPgV(1r7NcO37==rnV@9*l?ytF7Mj8(-CTy> Date: Sat, 13 Sep 2025 17:32:25 +0800 Subject: [PATCH 16/44] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=8D=A1=E9=85=8D=E6=96=B9=EF=BC=9B?= =?UTF-8?q?=E8=B0=83=E6=95=B4=E5=AE=9E=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8?= =?UTF-8?q?=E9=85=8D=E6=96=B9=EF=BC=9B=E6=B7=BB=E5=8A=A0jei=E5=AF=B9?= =?UTF-8?q?=E5=AE=9E=E4=BD=93=E5=8A=A0=E9=80=9F=E5=8D=A1=E7=9A=84=E6=B3=A8?= =?UTF-8?q?=E5=86=8C=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integration/jei/ExtendedAEJeiPlugin.java | 11 ++++++ .../recipes/entity_speed_card_x16.json | 37 +++++++++++++++++++ .../recipes/entity_speed_card_x2.json | 30 +++++++++++++++ .../recipes/entity_speed_card_x4.json | 34 +++++++++++++++++ .../recipes/entity_speed_card_x8.json | 34 +++++++++++++++++ .../recipes/entity_speed_ticker.json | 28 ++++++++++---- 6 files changed, 166 insertions(+), 8 deletions(-) create mode 100644 src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x16.json create mode 100644 src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x2.json create mode 100644 src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x4.json create mode 100644 src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x8.json diff --git a/src/main/java/com/extendedae_plus/integration/jei/ExtendedAEJeiPlugin.java b/src/main/java/com/extendedae_plus/integration/jei/ExtendedAEJeiPlugin.java index 1294f17..5248037 100644 --- a/src/main/java/com/extendedae_plus/integration/jei/ExtendedAEJeiPlugin.java +++ b/src/main/java/com/extendedae_plus/integration/jei/ExtendedAEJeiPlugin.java @@ -1,8 +1,10 @@ package com.extendedae_plus.integration.jei; import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import mezz.jei.api.IModPlugin; import mezz.jei.api.JeiPlugin; +import mezz.jei.api.registration.ISubtypeRegistration; import mezz.jei.api.runtime.IJeiRuntime; import net.minecraft.resources.ResourceLocation; @@ -19,4 +21,13 @@ public class ExtendedAEJeiPlugin implements IModPlugin { public void onRuntimeAvailable(IJeiRuntime jeiRuntime) { JeiRuntimeProxy.setRuntime(jeiRuntime); } + + @Override + public void registerItemSubtypes(ISubtypeRegistration registration) { + // Register NBT-based subtype interpreter so JEI treats different multipliers as distinct items + registration.registerSubtypeInterpreter( + com.extendedae_plus.init.ModItems.ENTITY_SPEED_CARD.get(), + (stack, context) -> String.valueOf(EntitySpeedCardItem.readMultiplier(stack)) + ); + } } diff --git a/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x16.json b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x16.json new file mode 100644 index 0000000..821378b --- /dev/null +++ b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x16.json @@ -0,0 +1,37 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SAS", + "QXQ", + "SBS" + ], + "key": { + "S": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "nbt": { + "EAS:mult": 8 + } + }, + "A": { + "item": "minecraft:nether_star" + }, + "B": { + "item": "minecraft:beacon" + }, + "Q": { + "item": "ae2:spatial_cell_component_128" + }, + "X": { + "item": "minecraft:dragon_egg" + } + }, + "result": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "count": 1, + "nbt": { + "EAS:mult": 16 + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x2.json b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x2.json new file mode 100644 index 0000000..6c4466a --- /dev/null +++ b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x2.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SBS", + "QXQ", + "SBS" + ], + "key": { + "S": { + "item": "ae2:speed_card" + }, + "B": { + "item": "extendedae_plus:64x_crafting_accelerator" + }, + "Q": { + "item": "ae2:spatial_cell_component_2" + }, + "X": { + "item": "ae2:cell_component_256k" + } + }, + "result": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "count": 1, + "nbt": { + "EAS:mult": 2 + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x4.json b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x4.json new file mode 100644 index 0000000..91defa0 --- /dev/null +++ b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x4.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SBS", + "QXQ", + "SBS" + ], + "key": { + "S": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "nbt": { + "EAS:mult": 2 + } + }, + "B": { + "item": "extendedae_plus:256x_crafting_accelerator" + }, + "Q": { + "item": "ae2:spatial_cell_component_16" + }, + "X": { + "item": "ae2:dense_energy_cell" + } + }, + "result": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "count": 1, + "nbt": { + "EAS:mult": 4 + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x8.json b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x8.json new file mode 100644 index 0000000..73384f0 --- /dev/null +++ b/src/main/resources/data/extendedae_plus/recipes/entity_speed_card_x8.json @@ -0,0 +1,34 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "SBS", + "QXQ", + "SBS" + ], + "key": { + "S": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "nbt": { + "EAS:mult": 4 + } + }, + "B": { + "item": "extendedae_plus:1024x_crafting_accelerator" + }, + "Q": { + "item": "ae2:spatial_cell_component_128" + }, + "X": { + "item": "minecraft:nether_star" + } + }, + "result": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "count": 1, + "nbt": { + "EAS:mult": 8 + } + } +} \ No newline at end of file diff --git a/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json b/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json index df4ee1d..076d943 100644 --- a/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json +++ b/src/main/resources/data/extendedae_plus/recipes/entity_speed_ticker.json @@ -6,16 +6,28 @@ "SIS" ], "key": { - "S": { "item": "ae2:speed_card" }, - "Z": { "item": "ae2:dense_energy_cell" }, - "Q": { "item": "ae2:singularity" }, - "X": { "item": "minecraft:nether_star" }, - "I": { "item": "expatternprovider:ex_io_port" } + "S": { + "type": "forge:partial_nbt", + "item": "extendedae_plus:entity_speed_card", + "nbt": { + "EAS:mult": 2 + } + }, + "Z": { + "item": "ae2:dense_energy_cell" + }, + "Q": { + "item": "ae2:singularity" + }, + "X": { + "item": "minecraft:nether_star" + }, + "I": { + "item": "expatternprovider:ex_io_port" + } }, "result": { "item": "extendedae_plus:entity_speed_ticker", "count": 1 } -} - - +} \ No newline at end of file From ab0c913021960667429b06a13c1692e863e2c685 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sat, 13 Sep 2025 19:29:01 +0800 Subject: [PATCH 17/44] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=97=A0?= =?UTF-8?q?=E7=BA=BF=E6=94=B6=E5=8F=91=E5=99=A8=E5=8F=AA=E8=83=BD=E4=BC=A0?= =?UTF-8?q?=E9=80=928=E9=A2=91=E9=81=93=E7=9A=84=E9=97=AE=E9=A2=98?= =?UTF-8?q?=EF=BC=9B=E4=BF=AE=E5=A4=8D=E6=97=A0=E7=BA=BF=E6=94=B6=E5=8F=91?= =?UTF-8?q?=E5=99=A8=E4=B8=8E=E7=BA=BF=E7=BC=86=E8=BF=9E=E6=8E=A5=E5=A4=84?= =?UTF-8?q?=E6=B8=B2=E6=9F=93=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WirelessTransceiverBlockEntity.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java b/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java index c8e4c6d..9b2830e 100644 --- a/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java +++ b/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java @@ -1,6 +1,7 @@ package com.extendedae_plus.content.wireless; import appeng.api.networking.*; +import appeng.api.util.AECableType; import com.extendedae_plus.init.ModBlockEntities; import com.extendedae_plus.init.ModItems; import com.extendedae_plus.wireless.IWirelessEndpoint; @@ -16,6 +17,7 @@ import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; import java.util.EnumSet; +import java.util.Objects; /** * 无线收发器方块实体(骨架): @@ -38,7 +40,8 @@ public class WirelessTransceiverBlockEntity extends BlockEntity implements IWire public WirelessTransceiverBlockEntity(BlockPos pos, BlockState state) { super(ModBlockEntities.WIRELESS_TRANSCEIVER_BE.get(), pos, state); // 创建 AE2 管理节点 - this.managedNode = GridHelper.createManagedNode(this, NodeListener.INSTANCE); + this.managedNode = GridHelper.createManagedNode(this, NodeListener.INSTANCE) + .setFlags(GridFlags.DENSE_CAPACITY); this.managedNode.setIdlePowerUsage(1.0); // 可按需调整基础待机功耗 this.managedNode.setTagName("wireless_node"); this.managedNode.setInWorldNode(true); @@ -50,6 +53,20 @@ public class WirelessTransceiverBlockEntity extends BlockEntity implements IWire this.slaveLink = new WirelessSlaveLink(this); } + @Override + public appeng.api.util.AECableType getCableConnectionType(Direction dir) { + // 根据相邻方块的实际连接类型渲染(优先采用相邻主机返回的类型),回退为 GLASS。 + if (this.level == null) return AECableType.GLASS; + var adjacentPos = this.worldPosition.relative(dir); + if (!Objects.requireNonNull(this.getLevel()).hasChunkAt(adjacentPos)) return AECableType.GLASS; + var adjacentHost = GridHelper.getNodeHost(this.getLevel(), adjacentPos); + if (adjacentHost != null) { + var t = adjacentHost.getCableConnectionType(dir.getOpposite()); + if (t != null) return t; + } + return AECableType.GLASS; + } + /* ===================== IInWorldGridNodeHost ===================== */ @Override public @Nullable IGridNode getGridNode(Direction dir) { From 0354d86abf79661d8a23fa1c0c8d2d041f88e44d Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sat, 13 Sep 2025 21:44:49 +0800 Subject: [PATCH 18/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8=20tooltip=20=E6=96=87=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae/items/EntitySpeedTickerPartItem.java | 15 +++++++++++++++ .../assets/extendedae_plus/lang/en_us.json | 4 ++++ .../assets/extendedae_plus/lang/zh_cn.json | 4 ++++ 3 files changed, 23 insertions(+) diff --git a/src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java b/src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java index 7cb982d..d69893e 100644 --- a/src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java +++ b/src/main/java/com/extendedae_plus/ae/items/EntitySpeedTickerPartItem.java @@ -1,6 +1,12 @@ package com.extendedae_plus.ae.items; import appeng.items.parts.PartItem; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.Nullable; +import java.util.List; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; @@ -8,4 +14,13 @@ public class EntitySpeedTickerPartItem extends PartItem { public EntitySpeedTickerPartItem(Properties properties) { super(properties, EntitySpeedTickerPart.class, EntitySpeedTickerPart::new); } + + @Override + public void appendHoverText(ItemStack stack, @Nullable Level world, List tooltip, TooltipFlag flag) { + super.appendHoverText(stack, world, tooltip, flag); + // 中文 tooltip:提示需要放入实体加速卡开始加速,显示最大加速倍率和能量消耗说明 + tooltip.add(Component.translatable("item.extendedae_plus.entity_speed_ticker.tip.requirement", "需要放入实体加速卡以启用加速")); + tooltip.add(Component.translatable("item.extendedae_plus.entity_speed_ticker.tip.max", "最高可达 1024x 加速")); + tooltip.add(Component.translatable("item.extendedae_plus.entity_speed_ticker.tip.energy", "加速将消耗 AE 网络能量,网络能量不足时无法加速")); + } } \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 7dde8f6..561e56c 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -50,6 +50,10 @@ "screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d", "screen.extendedae_plus.entity_speed_ticker.multiplier": "Extra consumption multiplier: %s", + "item.extendedae_plus.entity_speed_ticker.tip.requirement": "Requires Entity Acceleration Card(s) to enable acceleration", + "item.extendedae_plus.entity_speed_ticker.tip.max": "Maximum up to 1024x speed", + "item.extendedae_plus.entity_speed_ticker.tip.energy": "Acceleration consumes AE network power; insufficient power disables acceleration", + "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "Wireless Transceiver Info", "config.jade.plugin_extendedae_plus.wt_frequency": "Show Frequency", "config.jade.plugin_extendedae_plus.wt_master_mode": "Show Master/Slave Mode", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 7126a2c..8a98475 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -50,6 +50,10 @@ "screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d", "screen.extendedae_plus.entity_speed_ticker.multiplier": "额外消耗倍率: %s", + "item.extendedae_plus.entity_speed_ticker.tip.requirement": "需要放入实体加速卡以启用加速", + "item.extendedae_plus.entity_speed_ticker.tip.max": "最高可达 1024x 加速", + "item.extendedae_plus.entity_speed_ticker.tip.energy": "加速将消耗 AE 网络能量,网络能量不足时无法加速", + "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "无线收发器信息", "config.jade.plugin_extendedae_plus.wt_frequency": "显示频率", "config.jade.plugin_extendedae_plus.wt_master_mode": "显示主/从模式", From d1ff87df2ffdfcd3901e4a779fe6de3a50f959ea Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sat, 13 Sep 2025 23:18:30 +0800 Subject: [PATCH 19/44] =?UTF-8?q?feat:=20eae=E6=89=A9=E5=B1=95=E6=A0=B7?= =?UTF-8?q?=E6=9D=BF=E7=AE=A1=E7=90=86=E7=95=8C=E9=9D=A2=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?f=E9=94=AE=E6=90=9C=E7=B4=A2=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/extendedae_plus/client/InputEvents.java | 11 +++++++++-- .../accessor/GuiExPatternTerminalAccessor.java | 4 ++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/extendedae_plus/client/InputEvents.java b/src/main/java/com/extendedae_plus/client/InputEvents.java index 44e9f85..50ee7b2 100644 --- a/src/main/java/com/extendedae_plus/client/InputEvents.java +++ b/src/main/java/com/extendedae_plus/client/InputEvents.java @@ -7,8 +7,10 @@ import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.init.ModNetwork; import com.extendedae_plus.integration.jei.JeiRuntimeProxy; import com.extendedae_plus.mixin.ae2.accessor.MEStorageScreenAccessor; +import com.extendedae_plus.mixin.extendedae.accessor.GuiExPatternTerminalAccessor; import com.extendedae_plus.network.OpenCraftFromJeiC2SPacket; import com.extendedae_plus.network.PullFromJeiOrCraftC2SPacket; +import com.glodblock.github.extendedae.client.gui.GuiExPatternTerminal; import mezz.jei.api.ingredients.ITypedIngredient; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.screens.Screen; @@ -96,13 +98,18 @@ public final class InputEvents { var screen = Minecraft.getInstance().screen; if (screen instanceof MEStorageScreen me) { try { - MEStorageScreenAccessor acc = (MEStorageScreenAccessor) (Object) me; + MEStorageScreenAccessor acc = (MEStorageScreenAccessor) me; acc.eap$getSearchField().setValue(name); acc.eap$setSearchText(name); // 同步到 Repo 并刷新 event.setCanceled(true); - return; } catch (Throwable ignored) { } + }else if (screen instanceof GuiExPatternTerminal gpt) { + try { + GuiExPatternTerminalAccessor acc = (GuiExPatternTerminalAccessor) gpt; + acc.getSearchOutField().setValue(name); + event.setCanceled(true); + }catch (Throwable ignored) {} } } } diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/accessor/GuiExPatternTerminalAccessor.java b/src/main/java/com/extendedae_plus/mixin/extendedae/accessor/GuiExPatternTerminalAccessor.java index dc7dd9c..a4e0516 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/accessor/GuiExPatternTerminalAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/accessor/GuiExPatternTerminalAccessor.java @@ -1,5 +1,6 @@ package com.extendedae_plus.mixin.extendedae.accessor; +import appeng.client.gui.widgets.AETextField; import appeng.client.gui.widgets.Scrollbar; import com.glodblock.github.extendedae.client.gui.GuiExPatternTerminal; import net.minecraftforge.api.distmarker.Dist; @@ -20,4 +21,7 @@ public interface GuiExPatternTerminalAccessor { @Accessor("rows") ArrayList getRows(); + + @Accessor("searchOutField") + AETextField getSearchOutField(); } \ No newline at end of file From 981d7c923ea0dfffa8a217008406e4d1566210c7 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sun, 14 Sep 2025 02:11:46 +0800 Subject: [PATCH 20/44] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=8D=A1=E6=B7=BB=E5=8A=A0=E5=8A=A8=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textures/item/entity_speed_card_x16.png | Bin 2323 -> 2485 bytes .../item/entity_speed_card_x16.png.mcmeta | 15 +++++++++++++++ .../textures/item/entity_speed_card_x2.png | Bin 2084 -> 2271 bytes .../item/entity_speed_card_x2.png.mcmeta | 15 +++++++++++++++ .../textures/item/entity_speed_card_x4.png | Bin 2326 -> 2501 bytes .../item/entity_speed_card_x4.png.mcmeta | 15 +++++++++++++++ .../textures/item/entity_speed_card_x8.png | Bin 2307 -> 2476 bytes .../item/entity_speed_card_x8.png.mcmeta | 15 +++++++++++++++ 8 files changed, 60 insertions(+) create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png.mcmeta create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png.mcmeta create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png.mcmeta create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png.mcmeta diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png index 74e75d30731dd8fca0610ffbcee9fab9a3eae780..adfcc54a61cacbeaf5785fe622850a3a8549da53 100644 GIT binary patch delta 1118 zcmbO%v{iV5IF|wk8v_G_bmxyV8x_l#cr0}d4MPmgtqe`9j3+N6P~^D1|9$EEKaQC%Tcq*QO=D}Tt5Dm6 zMI9Y1^$DE1Y8P4+9UC7kT4Zp#EoX7}f@O=u9EDa+_{*B9{l6hhk0+>5X70@L^m~6k zZ7qvBC)OCrOA&p#PftXbuB z*(6Ku{=}G~o68s+-qzUtl;)JV{(j-{MItUfTUK~Fs`$hi9B}!rDm7Q={quUJ0A?|T zr7R{Qa|*d_^8z!DUGSaU6u{wr!$Fu$c=P=g_T|&orPMU9VV-(0izTtgJlK%$~&Fp61RvlpbV%eidx?eUN5ESF7tveA> ztY5h=HOEb0wm_t@$JBsl@vg#-@9Il8%W*uIC3jFDG0m@B$#v0e$u}<;t*)H>mfI-w z-e?uar)B$uXB+JJ@Rxb>@>?5}3?FT(DPY@G&gm+lu~6V_@#8bswoPIX%Bq)}c&FxE zPsNNw&Vhk~vkp5RUJ>mj91y0Tu*W4_&E$#JI_V0N9?9z)nHVT)2UrAb&AD>sJ9-lIcp<(9o;s4H_si>tnD}qyFEPKEub;Z}zp(n0n)*5osn)K!nzOrBu8`=`&F0i>+~*$7u;J^M zrK~wi=bc@$xUcx!LB-#<7gieB*yuQJY7x7?XzC+Jop0ebFD}j9@nqBD&kCUMwK!|Q zn#N(PVsZc4nLX(;)fydIO(iB@Q|BM^k-JhJ`|SG->p2gdKRkGHwrtJU~`@hliT6uzWK9);TxrOZ=M}I^5jYV zfo5CdhFrM`PY(FaKiO={%6Gc?icXI1o8!$d7k!HLwK3xV$G{yqA&Z6oaSE^;VeoYI Kb6Mw<&;$U~*28!J delta 949 zcmdlgJXvUhIF|qi8v_G_{OA9P8x_l#cr0{{%t8!|tV}Je3@0yUQsOcWF)*|;GO{u@ zpM0K48JYWsDNxDO($dtz%v3kg*vv>b#mFR4*D}q}NY@}a)hyNA!rU}1ZE`-dwz7$- zL9(fFag2u5swyUiNvUQjDJHsxrYV-X zmKG+dx=Dr>mO%5;j1AKa%u-BKOeeFkgb}B(fkgz>KMPpORnihu(=04440Mgm%`J3O zO-(Fx6D<*h|s6t2w$nGKA zJ3BOG(N?}B)BYXNPd7Zils)x@q0TRz*(GVB?&poxy3V+!)brDn!HS_pfQMr;<7$up ze)IM%I=A|XZ`BvwUG>{HyKLVaV_7}%+>gMZWsavzBG%7bE64Cf($&OWpp2#8?%v~{ zKT4ZgWf*TODX_deqqR8Q&-kzPe#Z+YFHAqJIP~b;)h z?gQ(Dmb~FE%+fr`<(afmBFo~;jm@qrZ@Mt3t{2vM_du90TUj_HRWh7YnWKks zr%fy-W!(-p%!(ot|NWg@yF9n--{pPJt2wgleLl?PI@^UoGO}Q>G1UI>00lM teTRB~i(3?>FXR>cv0TEz>P7iK*2qmaF diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png.mcmeta b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png.mcmeta new file mode 100644 index 0000000..c488c5a --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png.mcmeta @@ -0,0 +1,15 @@ +{ + "animation": { + "interpolate": true, + "frames": [ + { + "index": 0, + "time": 32 + }, + { + "index": 1, + "time": 16 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png index 950d6235b841728e91ca61bca4531f8c5df3cc3f..043aa0238e3675d137f248c26a9a2934838b3975 100644 GIT binary patch delta 1046 zcmZ1?a9?nOIF|wk8v_G_bmxyV8x_l#cr0}d4MPmgtqe`9j3+Nzi;SxQ>6u3@63iLP;qiG{9(rIER=v4N$Tg{eiVS(@bO2F4bFYOea0OeO&i7KV(RET_vRv)tvq z;&z%TGu$|N@A#D5<(VF87bkO`dMp-oXpxQFVM$J7>x$;G{v*Gi#xt0t^G(^rl%Y`( zWL9-**&(k*(PB?8YP_4#spgX=zW;L7SFXR-UvoF{Ie1)2SZl3#P)35yf68LhUQSQp!v_1|h$$A@iO z`P&V4{(H>aExvo>W6z*XHCveP?r&4_nUXQ(+)_y~{gR1nmsU-#$ds&~uD)z$`m9r@ zyiB&w-gdGuv%g{2OZUD=kCi6ey0I#$tu2ctO)!1bHBEOiSDZ@XERDjc6Z`eQuV*%} z__XxF_dEG49#f}XdUsN0gFX9|Rd?Fn^x7ySSeE9s=iIWr)cEGQO|{wIxX6c@=jYxP zV{lq0b*kLDx~Mm7frMY>nYOik`s-2{Vt`l ziY?rvNlWQV*&X{orq4bv*!o|se%ZZ;opT%5pR-qOXii`8neVXJl6YR(e)fYKIb{wV zi7n0VdMnPnp_WNbqyOH9zjwTMEwSL=GkNmS$_d{pJvG@Y4Xn+-%YRs~fceH#Mr)Z9 z=YLlQ1Uy(`bHeudZfEEAPYW(EeCL>B@{eiD+$meW{zyy(=6?oHS3j3^P6Ba@ppurDnr2~XVW4YdZf>EQYHDJkn`n_}u4`dtW^8G0V32BTU^=;gSxdzv zIW;la+|*DvB{|7NH#rrkFv$!^B&V5Mq$L@er2v&q-p8z>Vq%z-YL=2>qHAcHVySCs zVUntwWN2ZjYml5~Y?x+XmSUP>I+=|nj5vi2EF!30TEJ3HoTD39#F0I_ki};54A%Vm zrJ8C>85o!tJzX3_EP9tt-k2?1D019B{oN#Qy`3#vwnWV83wj-JREcq6^MfY=x}pac zI*W@RbX*~DbfMl+zg?a(B?3H2nk(uXdxQTosJB~fSvY-3`Of%vdgUKwk}fUtEPN3y z_owcC?Y-}N@Bj8plqeFL%*fTsdaC$hl%D2!#cLaG#O(C6)BX7FxGUr^q*-v6YLW~7>RW2p&q1Lx+xcN~-Y9vof%e9ydkhc#h}S>_#Fg{zw667H;7 z)XC<*e@$^lq)z?a17du)r%#`-C(QleM#%+-dt~gHdZa`{EL}wy;;m5z4T^E-ExB;4} zOzO41vM*Ij%!?Qv94mP@OY!FxlLx%Icc*`;E}x!W{!V@?L&CA+D{TIqU{yWH@2b4` z$jz=*JG#2oy7=cV=_cQjh=u diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png.mcmeta b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png.mcmeta new file mode 100644 index 0000000..c488c5a --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x2.png.mcmeta @@ -0,0 +1,15 @@ +{ + "animation": { + "interpolate": true, + "frames": [ + { + "index": 0, + "time": 32 + }, + { + "index": 1, + "time": 16 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png index 1c440cc5d52c9a6d175d3c68e1021627a4fed8a4..ab8775fce0e9022cc82cdf2fc5979b44aa293f23 100644 GIT binary patch delta 1138 zcmbOxbX0hPIF|wk8v_G_bmxyV8x_l#cr0}d4MPmgtqe`9j3+N}a&n@%K~hSRrLn2S;Zj2e2Bxc?E{-7{ooA<<_7@HmY2V){Im0NG?O=z1oVEN8hsA~x z!eUb4dKE0Hg@MAcGbDrql??ZZNnPv+Q_K@dHo52`#?<*qoMYV&=9q~g!V?X?SYGyv z@9EywJXLIJp3Q9Io!`&ApI7|Oc7DQbv!ydQ9(?{OBf9?jZ1IG8DK>_>{qhaZriqET zCSHHr-Q>RJJO_hK?7D?nroNX?X0JHOaxbm5V?5qQ;TlE>HVleI==RcfGY@1s6Rjb#U)+~Il4{{8a&UVDXA3{#%6%sOjub|QoCK~X7Y ztMkY7H~9W{y!%PX^mO+Zxq7?4>}+P?hXO$KdF6*$4cA{UH56H(xZ}{bhI5O}!zEtZ zv_FeKv{pZGslKtLxwB9FlK87H!cEngm$&@7z||%B@K^h9mcxlQ^6my_BsN$77I@U@ z!?ynmgXk@n>$47o)pFkK`LJkjKiB04CzfA7^Y-PjK6TH|q>FMEOsoDepERkTuqe># zx%!OTcU`4CPES2@di4!+qjM&YuUxyfXvbX{iM{$yI8SI>C7p5dSUNNJwUVZniptEE z6#~?xBMn!r)yTT?B%oZK`?2tjMS>~DPVXOnW?jBffuFCm{8R0l zr_U-jd@d{DFDu~Yo#)8m@ay5t`p1qR&T)t?YkYl2V)b{w!>`mT6nJgYzpiU9i7b?> zaC7hetYG^_QFZO}gHNtpsXx%%BzZuJ|3uM)@b%hKx~@hVGuhASJQ35&JqJWXhVIF|qi8v_G_{OA9P8x_l#cr0{{%t8!|tV}Je3@0yUQsOcWF)*|;GPE)^ zn0%f|8JYWsDL}&oEp&mdGuO2+Gc&d{H!w&wHZYysz#rN*I1|~I67sn8b-ldZ_`U@vY9IJPKpS|98$D|-dAq74@4z;TuKElFm z!s_e+hAMnKI(llS4lOFY(0Za_m!!;*BMS{hgjHU~ygVlVAfe}=gn~@#y}QTnZdH9A z5UrCS^JAL%&wbBp?>(=+_dT>p;em-e>xt)|86EVdJA2)%XPMB)?65I{Wx@9K{ISOf|~g*B+Z_m?9#z1$|dsZ}(lxVcdI+z!EX4^xH=#tA`}v~{cA##VhR zdvVXS()fRaU-9I=x4iYYwwv#$eXDlyNu*I&XHRI-+AP^Bh6}N`juxn{UH9bY@#TBu z_W3W_;d)~ur?=;}4Nk9Ki5~m^;5C;NOYBnFlFZK)m2I}ClOBE6=_`rcYtr^;dN$X; zPYld#S6(POUb^En*(^Uexn=3$uln2~Z0?+YxI#n!?q@oD$HjwvqUzfYwF>ez zFzYtScNJEa&GSDq*+b<*bhKoZ>0%SX3~RMjuNQ{!N61PnT*P(CY4Ms@Kb+Pdo+8Zd zX~lQw`iy@c9=)(;n0&cg{hs+PjsV_PkK@^_ea9AEyXdjP|A`@!ep119kqLd;#}}OlH5i ybg8p&{T<8mzgt_Ag&5_0eg9r&e!AuLAL$mU2OG;7l~jPal)=;0&t;ucLK6TjwsT$p diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png.mcmeta b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png.mcmeta new file mode 100644 index 0000000..c488c5a --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x4.png.mcmeta @@ -0,0 +1,15 @@ +{ + "animation": { + "interpolate": true, + "frames": [ + { + "index": 0, + "time": 32 + }, + { + "index": 1, + "time": 16 + } + ] + } +} \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png index 1b51f61e79ea7abcbfa069b2dd18277a57b45027..dbfdae5b48127a7c29b6c395ce4b413f8542b4f9 100644 GIT binary patch delta 1110 zcmZn`S|dC`oJ)a&je&tdy7R}Gjf!PVJeInKh9QRLR)!{4#*-H_DRG*F7#LX@m{=K1 zKF6ej#QV(@sFIXoWNMUZV4`c5l$@$-nQCIDo0Mj1q-$)JVw`GWU~HL`m@>J5SxY&| z)XXe3#mHROJlVoX*T~q!RM#TaEK%3g#MmM+&BD;sFm>`?W>uABi$udj3o}z)}H4x%ffmWEC8l(a}V{Du@8K{#N7!p9g8(NtfSQ(g3UdUoIc?PQwab8AfhXkED zRJ+*ZYPQJwCa?M(3=B+rJY5_^JUY)#IqNM_C~@3=vGMCQi#IP@B=O4dG@q2GM3bW+ zt8C3dA*(eB?2b&#o=uCKCwZ1#Y!2{B5!m9Qwf7I>#IjHP8XWv=D|fuxwfpn!xwXYs zYu3GcrL}JQywl9a=WFWk-#0%0d7{qgM;40AA6^FqEzRF!x3u0tf{j70pS@w#t1J`W z$6qGfoz$G3&&lwedH#v}J;9aQU2?qv5@r{b)LI`3R5IFMz8jud;;|?459fi*4Gfx^ z3l=`;hB+E%mFq zyJyZ0@0r!DleVUIU7MC!pTDbd?-r)%_uEguPgZ<(|E1&o3ft@JD=s=WHBCtPa5(wc ztm+e=*CZJ;-Do-SLZPy?=)Tn~jt?I`8%WpLpVL>CP&yJ*%N}GgsbIru_7?%#x64_) z?yg>;bRZ>`-7K--=WmhE>Cqbx1tx8(*};5wZ<7+wl!OV-Sj9i5M|Ch4n)cThxU zQ=5_6^ypF2mL?`CxAvtXjHP#bWsD{!6+X*~?l{FI=&Gue-6ER1+sAA6;+6&jo+%qn z9oYT+<$J~#azA#w|NJC>j?52V9rNjK?vEP2yb1K4A?N4w=$p$j4u%<(R_3*0y?mMe zW!ZgG`v2+Zeq8akEK9idn^D;B`^8=->z}tT3S4qy=GK)ny1EwLFp5*u47h8}>hQby z(Uhj#*E5~0-dR1Di7P5dIorH&;leA9R$Bb`j)mzikEyGXQvn97e7oeL3p|V1S;eDg zN6slotD$D}UCmTN}*$0v^6$*FO?}$5M*ljLm%m zCv$A|d5PKQcO@8e%V~U%+xYW}r;WNX|D45(XI2Wx7YPM_`;<_X_RRjl!F_xQ?d&;) z3FUsz5AI{S`AK2px!u!VI>=qAxqbOa^5+NghhFsV*I&8rAh7&k@O1TaS?83{1OP6= By_Wz0 delta 934 zcmZ1@+$=OfoJ)X%je&td{`3FDjf!PVJQlh}W+4VfR;CtKhLaaFDRCNy7#La^83B3c zm{gE>znKD6l2eThjg1V=bWM%Y%ybPbO-yu?OwCMnO%e^$ERs_bjVvrICl@elDW_Oi zTAG@gS?XGt8CmKY8vzws7$=+SCK{%go28m0nqHAcHVySCs zVUntwWN2ZjYml5~Y?x+XmSUP>I+=|nj5vi2EF!4>S-?`Rl9rg7W?^Yzplf7qZlRlM zYGR?AXpv|RbeWm4rMZDYsB|%zLuul4}dQT$viV znkGAEujJs9?NaD?pm27>ar}J?8Y2yhPrisSk3(YGK(Bhl8{Nejr-A6ce*N`-xAEHRFsv9G2xn!U|<6W;+&21ORdM1fV)W@v~@=s&HT zyW{-IKYGg5)-2!3>LWVhj@wqvni8m(8ge5~y4{H3n6~PdT?eAYZR-C|nZCKaP_)?M ztd^f*pUMl)o=~ogMW-J77oKW6cU<|z+V|hhxH#?Uf8iHDV?`1dUCBC=xBSGM*^8M=Ld1F7+q>(tIn6u;c-SuP ziA#$+vNW!PAxp7;b;vQrS2@0CF9wO|T Date: Sun, 14 Sep 2025 14:02:25 +0800 Subject: [PATCH 21/44] =?UTF-8?q?feat:=20=E5=90=88=E6=88=90=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E7=95=8C=E9=9D=A2=EF=BC=8C=E6=8C=89=E4=BD=8Fshift?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E5=8F=96=E6=B6=88=E6=8C=89=E9=92=AE=EF=BC=8C?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=B0=86=E7=BC=BA=E5=A4=B1=E6=9D=90=E6=96=99?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=87=B3jei=E4=B9=A6=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integration/jei/JeiRuntimeProxy.java | 40 ++++++++++++++ .../ae2/menu/CraftConfirmMenuGoBackMixin.java | 52 +++++++++++++++++++ .../resources/extendedae_plus.mixins.json | 1 + 3 files changed, 93 insertions(+) create mode 100644 src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java diff --git a/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java b/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java index ce96613..3965a63 100644 --- a/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java +++ b/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java @@ -7,7 +7,9 @@ import mezz.jei.api.runtime.IBookmarkOverlay; import mezz.jei.api.runtime.IIngredientListOverlay; import mezz.jei.api.runtime.IJeiRuntime; import mezz.jei.gui.bookmarks.BookmarkList; +import mezz.jei.gui.bookmarks.IngredientBookmark; import mezz.jei.gui.overlay.elements.IElement; +import net.minecraft.world.item.ItemStack; import javax.annotation.Nullable; import java.util.Collections; @@ -132,4 +134,42 @@ public final class JeiRuntimeProxy { } return Collections.emptyList(); } + + /** + * 将物品添加到 JEI 书签 + */ + public static void addBookmark(ItemStack stack) { + IJeiRuntime rt = RUNTIME; + if (rt == null) return; + + IBookmarkOverlay overlay = rt.getBookmarkOverlay(); + if (overlay instanceof BookmarkOverlayAccessor accessor) { + BookmarkList list = accessor.eap$getBookmarkList(); + Optional> typedOpt = rt.getIngredientManager() + .createTypedIngredient(VanillaTypes.ITEM_STACK, stack); + typedOpt.ifPresent(typed -> { + IngredientBookmark bookmark = IngredientBookmark.create(typed, rt.getIngredientManager()); + list.add(bookmark); // add 内部会自动保存到配置 + }); + } + } + + /** + * 从 JEI 书签移除物品 + */ + public static void removeBookmark(ItemStack stack) { + IJeiRuntime rt = RUNTIME; + if (rt == null) return; + + IBookmarkOverlay overlay = rt.getBookmarkOverlay(); + if (overlay instanceof BookmarkOverlayAccessor accessor) { + BookmarkList list = accessor.eap$getBookmarkList(); + Optional> typedOpt = rt.getIngredientManager() + .createTypedIngredient(VanillaTypes.ITEM_STACK, stack); + typedOpt.ifPresent(typed -> { + IngredientBookmark bookmark = IngredientBookmark.create(typed, rt.getIngredientManager()); + list.remove(bookmark); + }); + } + } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java new file mode 100644 index 0000000..0bbc164 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java @@ -0,0 +1,52 @@ +package com.extendedae_plus.mixin.ae2.menu; + +import appeng.menu.me.crafting.CraftConfirmMenu; +import appeng.menu.me.crafting.CraftingPlanSummary; +import appeng.menu.me.crafting.CraftingPlanSummaryEntry; +import com.extendedae_plus.integration.jei.JeiRuntimeProxy; +import net.minecraft.client.gui.screens.Screen; +import org.spongepowered.asm.mixin.Mixin; +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; + +/** + * Inject into CraftConfirmMenu.goBack() after it finishes and read the plan entries. + */ +@Mixin(CraftConfirmMenu.class) +public class CraftConfirmMenuGoBackMixin { + + @Inject(method = "goBack", at = @At("RETURN"), remap = false) + private void afterGoBack(CallbackInfo ci) { + CraftConfirmMenu self = (CraftConfirmMenu) (Object) this; + + try { + // 只在客户端执行此逻辑,服务端直接返回 + if (!self.isClientSide()) return; + + // 检测本地客户端是否按下了 shift 键 + boolean shiftDown = false; + try { + shiftDown = Screen.hasShiftDown(); + } catch (Throwable ignored) {} + if (!shiftDown) return; + + // 获取合成计划摘要 + CraftingPlanSummary plan = self.getPlan(); + if (plan == null) return; + + // 获取合成计划条目列表 + List entries = plan.getEntries(); + if (entries == null || entries.isEmpty()) return; + + // 仅在按住 shift 时为缺失的条目添加 JEI 书签 + for (CraftingPlanSummaryEntry entry : entries) { + if (entry.getMissingAmount() > 0) { + JeiRuntimeProxy.addBookmark(entry.getWhat().wrapForDisplayOrFilter()); + } + } + } catch (Throwable ignored) {} + } +} \ No newline at end of file diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index 6b6f79d..5037016 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -46,6 +46,7 @@ "ae2.helpers.PatternProviderLogicAdvancedMixin", "ae2.helpers.PatternProviderLogicDoublingMixin", "ae2.menu.ContainerPatternEncodingTermMenuMixin", + "ae2.menu.CraftConfirmMenuGoBackMixin", "ae2.menu.MEStorageMenuMixin", "ae2.menu.PatternEncodingTermMenuMixin", "ae2.menu.PatternProviderMenuAdvancedMixin", From 6d45627cbe3adc42ff41348672270fdf2ba1d74e Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Sun, 14 Sep 2025 20:07:52 +0800 Subject: [PATCH 22/44] =?UTF-8?q?feat:=20=E5=86=85=E5=B5=8Cconfiguration?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E9=85=8D=E7=BD=AE=E7=95=8C=E9=9D=A2=E6=98=BE?= =?UTF-8?q?=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + build.gradle | 7 +- .../com/extendedae_plus/ExtendedAEPlus.java | 11 +- .../ae/menu/EntitySpeedTickerMenu.java | 6 +- .../ae/parts/EntitySpeedTickerPart.java | 6 +- .../client/ClientRegistrar.java | 18 +- .../client/ModConfigScreen.java | 172 ------------------ .../com/extendedae_plus/config/ModConfig.java | 120 ++++++++++++ .../extendedae_plus/config/ModConfigs.java | 111 ----------- .../mixin/ae2/EncodedPatternItemMixin.java | 4 +- .../autopattern/CraftingTreeProcessMixin.java | 4 +- .../client/gui/GuiExPatternProviderMixin.java | 6 +- .../client/gui/GuiExPatternTerminalMixin.java | 4 +- .../common/PartExPatternProviderMixin.java | 4 +- .../common/TileExPatternProviderMixin.java | 4 +- .../extendedae_plus/util/PatternScaler.java | 6 +- .../com/extendedae_plus/util/PowerUtils.java | 6 +- .../wireless/WirelessMasterRegistry.java | 4 +- .../wireless/WirelessSlaveLink.java | 6 +- .../assets/extendedae_plus/lang/en_us.json | 32 ++-- .../assets/extendedae_plus/lang/zh_cn.json | 32 ++-- .../resources/extendedae_plus.mixins.json | 1 + 22 files changed, 205 insertions(+), 360 deletions(-) delete mode 100644 src/main/java/com/extendedae_plus/client/ModConfigScreen.java create mode 100644 src/main/java/com/extendedae_plus/config/ModConfig.java delete mode 100644 src/main/java/com/extendedae_plus/config/ModConfigs.java diff --git a/README.md b/README.md index 835bf41..d8d6011 100644 --- a/README.md +++ b/README.md @@ -41,5 +41,6 @@ ExtendedAE Plus 是一个面向 Applied Energistics 2 与 ExtendedAE 的功能 - Applied Energistics 2(AE2):MIT License - SpongePowered Mixin:MIT License +- Configuration(by Toma):MIT License 请查阅各上游项目以获取完整与最新的许可证信息。第三方组件的许可证与版权归其各自作者所有。 diff --git a/build.gradle b/build.gradle index d0c7699..b63a799 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,7 @@ plugins { id 'dev.architectury.loom' version '1.10-SNAPSHOT' id 'maven-publish' + id 'com.github.johnrengelman.shadow' version '8.1.1' } group = project.maven_group @@ -80,7 +81,7 @@ dependencies { annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" - modCompileOnly "curse.maven:applied-flux-965012:${applied_flux_version}" + modCompileOnly "curse.maven:applied-flux-965012:${applied_flux_version}" modCompileOnly "curse.maven:mega-cells-622112:${mega_cells_version}" modCompileOnly "curse.maven:jade-324717:${jade_version}" @@ -115,6 +116,10 @@ dependencies { modRuntimeOnly "curse.maven:geckolib-388172:6920925" //mclib运行时 forgeRuntimeLibrary "com.eliotlash.mclib:mclib:20" + + // compileOnly 供代码编译 + include "curse.maven:configuration-444699:4710266" + modImplementation "curse.maven:configuration-444699:4710266" } allprojects { diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index aefcb30..5bc94d1 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -2,7 +2,7 @@ package com.extendedae_plus; import appeng.menu.locator.MenuLocators; import com.extendedae_plus.client.ClientRegistrar; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.init.*; import com.extendedae_plus.menu.locator.CuriosItemLocator; import net.minecraft.resources.ResourceLocation; @@ -11,10 +11,7 @@ import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.DistExecutor; -import net.minecraftforge.fml.ModLoadingContext; import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.config.ModConfig; import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent; import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent; import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; @@ -49,9 +46,9 @@ public class ExtendedAEPlus { // 注册到Forge事件总线 MinecraftForge.EVENT_BUS.register(this); - // 注册通用配置 - ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); + ModConfig.init(); +// ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); } /** @@ -89,7 +86,7 @@ public class ExtendedAEPlus { public static void onClientSetup(final FMLClientSetupEvent event) { // 直接在此处执行客户端一次性注册(UI/屏幕/渲染器绑定) // 注册客户端配置界面 - ClientRegistrar.registerConfigScreen(); +// ClientRegistrar.registerConfigScreen(); // 将 InitScreens 的注册委托给 ClientRegistrar,便于集中管理客户端注册逻辑 ClientRegistrar.registerInitScreens(); diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index 6eb75e2..2981e98 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -6,7 +6,7 @@ import appeng.menu.implementations.UpgradeableMenu; import appeng.menu.slot.OptionalFakeSlot; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModMenuTypes; import com.extendedae_plus.util.ConfigParsingUtils; @@ -16,6 +16,8 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraftforge.registries.ForgeRegistries; +import java.util.List; + // 实体加速器菜单,负责与客户端界面同步数据 public class EntitySpeedTickerMenu extends UpgradeableMenu { @GuiSync(716) public boolean accelerateEnabled = true; @@ -62,7 +64,7 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu compiledBlacklist = ConfigParsingUtils.getCachedBlacklist(ModConfigs.EntitySpeedTickerBlackList.get()); + List compiledBlacklist = ConfigParsingUtils.getCachedBlacklist(List.of(ModConfig.INSTANCE.entityTickerBlackList)); for (Pattern p : compiledBlacklist) { if (p.matcher(blockId).matches()) return; } @@ -228,7 +228,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka int speed = (int) product; double multiplier = 1.0; - for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(ModConfigs.EntitySpeedTickerMultipliers.get())) { + for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(List.of(ModConfig.INSTANCE.entityTickerMultipliers))) { if (me.pattern.matcher(blockId).matches()) { multiplier = Math.max(multiplier, me.multiplier); } diff --git a/src/main/java/com/extendedae_plus/client/ClientRegistrar.java b/src/main/java/com/extendedae_plus/client/ClientRegistrar.java index 61a24bc..0fa4b24 100644 --- a/src/main/java/com/extendedae_plus/client/ClientRegistrar.java +++ b/src/main/java/com/extendedae_plus/client/ClientRegistrar.java @@ -14,8 +14,6 @@ import com.extendedae_plus.init.ModItems; import com.extendedae_plus.init.ModMenuTypes; import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.renderer.item.ItemProperties; -import net.minecraftforge.client.ConfigScreenHandler; -import net.minecraftforge.fml.ModLoadingContext; /** * 客户端模型注册,将 formed 模型注册为内置模型。 @@ -76,12 +74,12 @@ public final class ClientRegistrar { * 仅客户端:在 Mods 菜单注册配置界面入口。 * 将对 Screen 的引用限制在客户端侧,避免服务端类加载。 */ - public static void registerConfigScreen() { - // 将 ModConfigScreen 的引用放在此处,确保仅在 Dist.CLIENT 下解析该类 - ModLoadingContext.get().registerExtensionPoint( - ConfigScreenHandler.ConfigScreenFactory.class, - () -> new ConfigScreenHandler.ConfigScreenFactory( - (mc, parent) -> new ModConfigScreen(parent)) - ); - } +// public static void registerConfigScreen() { +// // 将 ModConfigScreen 的引用放在此处,确保仅在 Dist.CLIENT 下解析该类 +// ModLoadingContext.get().registerExtensionPoint( +// ConfigScreenHandler.ConfigScreenFactory.class, +// () -> new ConfigScreenHandler.ConfigScreenFactory( +// (mc, parent) -> new ModConfigScreen(parent)) +// ); +// } } diff --git a/src/main/java/com/extendedae_plus/client/ModConfigScreen.java b/src/main/java/com/extendedae_plus/client/ModConfigScreen.java deleted file mode 100644 index 5a65d8d..0000000 --- a/src/main/java/com/extendedae_plus/client/ModConfigScreen.java +++ /dev/null @@ -1,172 +0,0 @@ -package com.extendedae_plus.client; - -import com.extendedae_plus.config.ModConfigs; -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiGraphics; -import net.minecraft.client.gui.components.Button; -import net.minecraft.client.gui.components.CycleButton; -import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.screens.Screen; -import net.minecraft.network.chat.Component; - -public class ModConfigScreen extends Screen { - private final Screen parent; - - // 输入控件 - private EditBox pageMultiplierBox; - private EditBox wirelessMaxRangeBox; - private CycleButton crossDimToggle; - private CycleButton providerRoundRobinToggle; - private EditBox smartScalingMaxMulBox; - private EditBox smartScalingMinBenefitBox; - private CycleButton showEncoderToggle; - private CycleButton patternTerminalShowSlotsToggle; - - public ModConfigScreen(Screen parent) { - super(Component.translatable("screen.extendedae_plus.title")); - this.parent = parent; - } - - @Override - protected void init() { - int centerX = this.width / 2; - int y = this.height / 6 + 24; // 起始高度,整体更上方 - int row = 0; - int rowHeight = 26; - int boxWidth = 150; - // 左右两列:左侧标签起点,右侧输入控件起点 - int leftX = centerX - 170; - int rightX = centerX + 20; - - // pageMultiplier: Int 1-64 - pageMultiplierBox = new EditBox(this.font, rightX, y + row * rowHeight, boxWidth, 20, Component.translatable("config.extendedae_plus.pageMultiplier")); - pageMultiplierBox.setValue(String.valueOf(ModConfigs.PAGE_MULTIPLIER.get())); - pageMultiplierBox.setFilter(s -> s.matches("\\d*") && parseIntOrDefault(s, 1) >= 1 && parseIntOrDefault(s, 64) <= 64); - this.addRenderableWidget(pageMultiplierBox); - row++; - - // wirelessMaxRange: Double 1-4096 - wirelessMaxRangeBox = new EditBox(this.font, rightX, y + row * rowHeight, boxWidth, 20, Component.translatable("config.extendedae_plus.wirelessMaxRange")); - wirelessMaxRangeBox.setValue(String.valueOf(ModConfigs.WIRELESS_MAX_RANGE.get())); - wirelessMaxRangeBox.setFilter(s -> s.isEmpty() || s.matches("\\d*(\\.\\d*)?")); - this.addRenderableWidget(wirelessMaxRangeBox); - row++; - - // cross dim toggle - crossDimToggle = this.addRenderableWidget(createToggle(rightX, y + row * rowHeight, boxWidth, 20, ModConfigs.WIRELESS_CROSS_DIM_ENABLE.get())); - row++; - - // provider round-robin toggle (smart doubling) - providerRoundRobinToggle = this.addRenderableWidget(createToggle(rightX, y + row * rowHeight, boxWidth, 20, ModConfigs.PROVIDER_ROUND_ROBIN_ENABLE.get())); - row++; - - // smartScalingMaxMultiplier: Int 0-1048576 (0 means unlimited) - smartScalingMaxMulBox = new EditBox(this.font, rightX, y + row * rowHeight, boxWidth, 20, Component.translatable("config.extendedae_plus.smartScalingMaxMultiplier")); - smartScalingMaxMulBox.setValue(String.valueOf(ModConfigs.SMART_SCALING_MAX_MULTIPLIER.get())); - smartScalingMaxMulBox.setFilter(s -> s.matches("\\d*") && parseIntOrDefault(s, 0) >= 0 && parseIntOrDefault(s, 1048576) <= 1048576); - this.addRenderableWidget(smartScalingMaxMulBox); - row++; - - // smartScalingMinBenefitFactor: Int 1-1024 - smartScalingMinBenefitBox = new EditBox(this.font, rightX, y + row * rowHeight, boxWidth, 20, Component.translatable("config.extendedae_plus.smartScalingMinBenefitFactor")); - smartScalingMinBenefitBox.setValue(String.valueOf(ModConfigs.SMART_SCALING_MIN_BENEFIT_FACTOR.get())); - smartScalingMinBenefitBox.setFilter(s -> s.matches("\\d*") && parseIntOrDefault(s, 1) >= 1 && parseIntOrDefault(s, 1024) <= 1024); - this.addRenderableWidget(smartScalingMinBenefitBox); - row++; - - // show encoder pattern player toggle - showEncoderToggle = this.addRenderableWidget(createToggle(rightX, y + row * rowHeight, boxWidth, 20, ModConfigs.SHOW_ENCOD_PATTERN_PLAYER.get())); - row++; - - // pattern terminal show slots default toggle - patternTerminalShowSlotsToggle = this.addRenderableWidget(createToggle(rightX, y + row * rowHeight, boxWidth, 20, ModConfigs.PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT.get())); - row++; - - // 按钮:保存、返回 - int btnW = 100; - int gap = 8; - int buttonsY = y + row * rowHeight + 18; - this.addRenderableWidget(Button.builder(Component.translatable("gui.done"), b -> saveAndClose()) - .pos(centerX - btnW - gap/2, buttonsY) - .size(btnW, 20) - .build()); - this.addRenderableWidget(Button.builder(Component.translatable("gui.cancel"), b -> onClose()) - .pos(centerX + gap/2, buttonsY) - .size(btnW, 20) - .build()); - } - - private void saveAndClose() { - // 读取与校验 - int pageMul = clamp(parseIntOrDefault(pageMultiplierBox.getValue(), ModConfigs.PAGE_MULTIPLIER.get()), 1, 64); - double maxRange = clamp(parseDoubleOrDefault(wirelessMaxRangeBox.getValue(), ModConfigs.WIRELESS_MAX_RANGE.get()), 1.0, 4096.0); - boolean crossDim = crossDimToggle.getValue(); - boolean providerRoundRobin = providerRoundRobinToggle.getValue(); - int smartMaxMul = clamp(parseIntOrDefault(smartScalingMaxMulBox.getValue(), ModConfigs.SMART_SCALING_MAX_MULTIPLIER.get()), 0, 1048576); - int smartMinBenefit = clamp(parseIntOrDefault(smartScalingMinBenefitBox.getValue(), ModConfigs.SMART_SCALING_MIN_BENEFIT_FACTOR.get()), 1, 1024); - boolean showEncoder = showEncoderToggle.getValue(); - boolean patternShowSlots = patternTerminalShowSlotsToggle.getValue(); - - // 应用到 Forge 配置值 - ModConfigs.PAGE_MULTIPLIER.set(pageMul); - ModConfigs.WIRELESS_MAX_RANGE.set(maxRange); - ModConfigs.WIRELESS_CROSS_DIM_ENABLE.set(crossDim); - ModConfigs.PROVIDER_ROUND_ROBIN_ENABLE.set(providerRoundRobin); - ModConfigs.SMART_SCALING_MAX_MULTIPLIER.set(smartMaxMul); - ModConfigs.SMART_SCALING_MIN_BENEFIT_FACTOR.set(smartMinBenefit); - ModConfigs.SHOW_ENCOD_PATTERN_PLAYER.set(showEncoder); - ModConfigs.PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT.set(patternShowSlots); - - // Forge 会在合适的时机写回到配置文件;部分改动可能需要重启游戏或世界才完全生效 - onClose(); - } - - // Helper to create a boolean on/off CycleButton which shows localized on/off text - private CycleButton createToggle(int x, int y, int width, int height, boolean initial) { - CycleButton btn = CycleButton.onOffBuilder(initial) - .create(x, y, width, height, Component.empty(), (b, v) -> b.setMessage(Component.translatable(v ? "config.extendedae_plus.state_on" : "config.extendedae_plus.state_off"))); - btn.setMessage(Component.translatable(initial ? "config.extendedae_plus.state_on" : "config.extendedae_plus.state_off")); - return btn; - } - - @Override - public void onClose() { - Minecraft.getInstance().setScreen(parent); - } - - @Override - public void render(GuiGraphics g, int mouseX, int mouseY, float partialTick) { - this.renderBackground(g); - super.render(g, mouseX, mouseY, partialTick); - - int centerX = this.width / 2; - int y = this.height / 6 + 24; - int rowHeight = 26; - int labelColor = 0xFFFFFF; - int leftX = centerX - 170; // 标签左列位置 - - // 标题 - g.drawCenteredString(this.font, this.title, centerX, y - 28, 0xFFFFFF); - - // 每行标签 - g.drawString(this.font, Component.translatable("config.extendedae_plus.pageMultiplier_with_range"), leftX, y + 0 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.wirelessMaxRange_with_range"), leftX, y + 1 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.wirelessCrossDimEnable"), leftX, y + 2 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.providerRoundRobinEnable"), leftX, y + 3 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.smartScalingMaxMultiplier_with_range"), leftX, y + 4 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.smartScalingMinBenefitFactor"), leftX, y + 5 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.showEncoderPatternPlayer"), leftX, y + 6 * rowHeight + 6, labelColor, false); - g.drawString(this.font, Component.translatable("config.extendedae_plus.patternTerminalShowSlotsDefault"), leftX, y + 7 * rowHeight + 6, labelColor, false); - } - - private static int parseIntOrDefault(String s, int def) { - try { return Integer.parseInt(s); } catch (Exception e) { return def; } - } - - private static double parseDoubleOrDefault(String s, double def) { - try { return Double.parseDouble(s); } catch (Exception e) { return def; } - } - - private static int clamp(int v, int min, int max) { return Math.max(min, Math.min(max, v)); } - private static double clamp(double v, double min, double max) { return Math.max(min, Math.min(max, v)); } -} diff --git a/src/main/java/com/extendedae_plus/config/ModConfig.java b/src/main/java/com/extendedae_plus/config/ModConfig.java new file mode 100644 index 0000000..2a5bd63 --- /dev/null +++ b/src/main/java/com/extendedae_plus/config/ModConfig.java @@ -0,0 +1,120 @@ +package com.extendedae_plus.config; + +import com.extendedae_plus.ExtendedAEPlus; +import dev.toma.configuration.Configuration; +import dev.toma.configuration.config.Config; +import dev.toma.configuration.config.Configurable; +import dev.toma.configuration.config.format.ConfigFormats; + + +@Config(id = ExtendedAEPlus.MODID) +public final class ModConfig { + + public static ModConfig INSTANCE; + private static final Object lock = new Object(); + + + public static void init() { + synchronized (lock) { + if (INSTANCE == null) { + INSTANCE = Configuration.registerConfig(ModConfig.class, ConfigFormats.yaml()).getConfigInstance(); + } + } + } + @Configurable + @Configurable.Comment(value = { + "扩展样板供应器总槽位容量的倍率。", + "基础为36,每页仍显示36格,倍率会增加总页数/总容量。", + "建议范围 1-16" + }) + @Configurable.Synchronized + @Configurable.Range(min = 1, max = 64) + public int pageMultiplier = 1; + + @Configurable + @Configurable.Comment(value = { + "无线收发器最大连接距离(单位:方块)", + "从端与主端的直线距离需小于等于该值才会建立连接" + }) + @Configurable.Synchronized + @Configurable.DecimalRange(min = 1, max = 4096) + public double wirelessMaxRange = 256.0; + + @Configurable + @Configurable.Comment(value = { + "是否允许无线收发器跨维度建立连接", + "开启后,从端可连接到不同维度的主端(忽略距离限制)" + }) + @Configurable.Synchronized + public boolean wirelessCrossDimEnable = true; + + @Configurable + @Configurable.Comment(value = { + "智能倍增时是否对样板供应器轮询分配", + "仅多个供应器有相同样板时生效,开启后请求会均分到所有可用供应器,关闭则全部分配给单一供应器", + "注意:所有相关供应器需开启智能倍增,否则可能失效" + }) + @Configurable.Synchronized + public boolean providerRoundRobinEnable = true; + + @Configurable + @Configurable.Comment(value = { + "智能倍增的最大倍数(0 表示不限制)", + "此倍数是针对单次样板产出的放大倍数上限,用于限制一次推送中按倍增缩放的规模" + }) + @Configurable.Synchronized + @Configurable.Range(min = 0, max = Integer.MAX_VALUE) + public int smartScalingMaxMultiplier = 0; + + @Configurable + @Configurable.Comment(value = { + "智能倍增最小收益因子(默认 4)", + "当目标请求量小于 perOperationTarget * 此因子 时,智能倍增将不被启用以避免无意义包装" + }) + @Configurable.Synchronized + @Configurable.Range(min = 1, max = 1024) + public int smartScalingMinBenefitFactor = 4; + + @Configurable + @Configurable.Comment(value = { + "是否显示样板编码玩家", + "开启后将在样板 HoverText 上添加样板的编码玩家" + }) + public boolean showEncoderPatternPlayer = true; + + @Configurable + @Configurable.Comment(value = { + "样板终端默认是否显示槽位", + "影响进入界面时SlotsRow的默认可见性,仅影响客户端显示" + }) + public boolean patternTerminalShowSlotsDefault = true; + + @Configurable + @Configurable.Comment(value = { + "实体加速器能量消耗基础值" + }) + @Configurable.Range(min = 0, max = Integer.MAX_VALUE) + @Configurable.Synchronized + public int entityTickerCost = 512; + + @Configurable + @Configurable.Comment(value = { + "实体加速器黑名单:匹配的方块将不会被加速。支持通配符/正则(例如:minecraft:*)", + "格式:全名或通配符/正则字符串,例如 'minecraft:chest'、'minecraft:*'、'modid:.*_fluid'" + }) + @Configurable.Synchronized + public String[] entityTickerBlackList = { + + }; + + @Configurable + @Configurable.Comment(value = { + "额外消耗倍率配置:为某些方块设置额外能量倍率,格式 'modid:blockid multiplier',例如 'minecraft:chest 2x'", + "支持通配符/正则匹配(例如 'minecraft:* 2x' 会对整个命名空间生效)。" + }) + @Configurable.Synchronized + public String[] entityTickerMultipliers = { + + }; + +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/config/ModConfigs.java b/src/main/java/com/extendedae_plus/config/ModConfigs.java deleted file mode 100644 index 623ab8d..0000000 --- a/src/main/java/com/extendedae_plus/config/ModConfigs.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.extendedae_plus.config; - -import net.minecraftforge.common.ForgeConfigSpec; - -public final class ModConfigs { - public static final ForgeConfigSpec COMMON_SPEC; - public static final ForgeConfigSpec.IntValue PAGE_MULTIPLIER; - public static final ForgeConfigSpec.DoubleValue WIRELESS_MAX_RANGE; - public static final ForgeConfigSpec.BooleanValue WIRELESS_CROSS_DIM_ENABLE; - public static final ForgeConfigSpec.BooleanValue SHOW_ENCOD_PATTERN_PLAYER; - public static final ForgeConfigSpec.BooleanValue PROVIDER_ROUND_ROBIN_ENABLE; - public static final ForgeConfigSpec.BooleanValue PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT; - public static final ForgeConfigSpec.IntValue SMART_SCALING_MAX_MULTIPLIER; - public static final ForgeConfigSpec.IntValue SMART_SCALING_MIN_BENEFIT_FACTOR; - public static final ForgeConfigSpec.IntValue EntitySpeedTickerCost; - public static final ForgeConfigSpec.ConfigValue> EntitySpeedTickerBlackList; - public static final ForgeConfigSpec.ConfigValue> EntitySpeedTickerMultipliers; - - - static { - ForgeConfigSpec.Builder builder = new ForgeConfigSpec.Builder(); - builder.push("extendedae_plus"); - PAGE_MULTIPLIER = builder - .comment( - "扩展样板供应器总槽位容量的倍率。", - "基础为36,每页仍显示36格,倍率会增加总页数/总容量。", - "建议范围 1-16") - .defineInRange("pageMultiplier", 1, 1, 64); - - // 无线收发器:最大连接距离(单位:方块)。 - // 一对多从端连接主端时,将以该值作为范围限制。 - WIRELESS_MAX_RANGE = builder - .comment( - "无线收发器最大连接距离(单位:方块)", - "从端与主端的直线距离需小于等于该值才会建立连接。") - .defineInRange("wirelessMaxRange", 256.0D, 1.0D, 4096.0D); - - // 是否允许跨维度连接(忽略维度差异进行频道传输)。 - WIRELESS_CROSS_DIM_ENABLE = builder - .comment( - "是否允许无线收发器跨维度建立连接", - "开启后,从端可连接到不同维度的主端(忽略距离限制)") - .define("wirelessCrossDimEnable", true); - - SHOW_ENCOD_PATTERN_PLAYER = builder - .comment( - "是否显示样板编码玩家", - "开启后将在样板 HoverText 上添加样板的编码玩家" - ) - .define("showEncoderPatternPlayer", true); - - // 智能倍增后,是否在样板供应器间轮询分配请求量(开启:按 provider 均分;关闭:不拆分) - PROVIDER_ROUND_ROBIN_ENABLE = builder - .comment( - "智能倍增时是否对样板供应器轮询分配", - "仅多个供应器有相同样板时生效,开启后请求会均分到所有可用供应器,关闭则全部分配给单一供应器", - "注意:所有相关供应器需开启智能倍增,否则可能失效", - "默认: true") - .define("providerRoundRobinEnable", true); - - // 智能倍增的最大倍数(以单次样板产出为单位)。 - // 0 表示不限制;>0 表示最大倍增倍数上限,例如 64 表示最多放大到 64 倍。 - SMART_SCALING_MAX_MULTIPLIER = builder - .comment( - "智能倍增的最大倍数(0 表示不限制)", - "此倍数是针对单次样板产出的放大倍数上限,用于限制一次推送中按倍增缩放的规模") - .defineInRange("smartScalingMaxMultiplier", 0, 0, 1048576); - - // 智能倍增最小收益因子:若 requestedAmount < perOperationTarget * 此因子,则不启用缩放(默认 4) - SMART_SCALING_MIN_BENEFIT_FACTOR = builder - .comment( - "智能倍增最小收益因子(默认 4)", - "当目标请求量小于 perOperationTarget * 此因子 时,智能倍增将不被启用以避免无意义包装") - .defineInRange("smartScalingMinBenefitFactor", 4, 1, 1024); - - // 模式访问终端(ExtendedAE 图样终端)默认是否显示槽位渲染(SlotsRow)。 - // true: 默认显示(可通过界面按钮临时隐藏);false: 默认隐藏(可通过按钮显示) - PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT = builder - .comment( - "样板终端默认是否显示槽位", - "影响进入界面时SlotsRow的默认可见性,仅影响客户端显示" - ) - .define("patternTerminalShowSlotsDefault", true); - - - builder.push("EntitySpeedTicker"); - EntitySpeedTickerCost = builder - .comment("实体加速器的能量消耗基础值") - .defineInRange("EntityTickerCost", 512, 0, Integer.MAX_VALUE); - - EntitySpeedTickerBlackList = builder - .comment( - "实体加速器黑名单:匹配的方块将不会被加速。支持通配符/正则(例如:minecraft:*)", - "格式:全名或通配符/正则字符串,例如 'minecraft:chest'、'minecraft:*'、'modid:.*_fluid'" - ) - .defineList("EntityTickerBlackList", java.util.List.of(), o -> o instanceof String); - - EntitySpeedTickerMultipliers = builder - .comment( - "额外消耗倍率配置:为某些方块设置额外能量倍率,格式 'modid:blockid multiplier',例如 'minecraft:chest 2x'", - "支持通配符/正则匹配(例如 'minecraft:* 2x' 会对整个命名空间生效)。" - ) - .defineList("EntityTickerMultipliers", java.util.List.of(), o -> o instanceof String); - builder.pop(); - - builder.pop(); - COMMON_SPEC = builder.build(); - } - - private ModConfigs() {} -} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/EncodedPatternItemMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/EncodedPatternItemMixin.java index 122d074..f8ebc9c 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/EncodedPatternItemMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/EncodedPatternItemMixin.java @@ -1,7 +1,7 @@ package com.extendedae_plus.mixin.ae2; import appeng.crafting.pattern.EncodedPatternItem; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import net.minecraft.ChatFormatting; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; @@ -20,7 +20,7 @@ public class EncodedPatternItemMixin { // 客户端:在 HoverText 显示样板的编码玩家 @Inject(method = "appendHoverText", at = @At("TAIL")) public void epp$appendHoverText(ItemStack stack, Level level, List lines, TooltipFlag advancedTooltips, CallbackInfo ci){ - if (stack.hasTag() && ModConfigs.SHOW_ENCOD_PATTERN_PLAYER.get()) { + if (stack.hasTag() && ModConfig.INSTANCE.showEncoderPatternPlayer) { CompoundTag tag = stack.getOrCreateTag(); String name = tag.getString("encodePlayer"); lines.add(Component.translatable("extendedae_plus.pattern.hovertext.player", name).withStyle(ChatFormatting.GRAY)); diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java index 68e510e..d6ce278 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java @@ -10,7 +10,7 @@ import appeng.crafting.CraftingTreeProcess; import appeng.crafting.pattern.AEProcessingPattern; import appeng.me.service.CraftingService; import com.extendedae_plus.api.SmartDoublingAwarePattern; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.content.ScaledProcessingPattern; import com.extendedae_plus.util.PatternScaler; import com.extendedae_plus.util.RequestedAmountHolder; @@ -58,7 +58,7 @@ public abstract class CraftingTreeProcessMixin { // 根据配置决定是否在 provider 间轮询分配请求量(默认开启) long perProvider = 1L; - if (!ModConfigs.PROVIDER_ROUND_ROBIN_ENABLE.get()) { + if (!ModConfig.INSTANCE.providerRoundRobinEnable) { // 关闭轮询:直接使用完整请求量,不需要查询 provider 列表 perProvider = requested; if (perProvider <= 0) perProvider = 1L; diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java index 42b1ce2..f101fda 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/client/gui/GuiExPatternProviderMixin.java @@ -6,7 +6,7 @@ import appeng.client.gui.style.ScreenStyle; import appeng.menu.SlotSemantics; import com.extendedae_plus.NewIcon; import com.extendedae_plus.api.ExPatternButtonsAccessor; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.glodblock.github.extendedae.client.button.ActionEPPButton; import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; import com.glodblock.github.extendedae.container.ContainerExPatternProvider; @@ -64,7 +64,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen 1) return cfg; } catch (Throwable ignored) {} try { @@ -123,7 +123,7 @@ public abstract class GuiExPatternProviderMixin extends PatternProviderScreen private void injectConstructor(CallbackInfo ci) { // 根据配置初始化默认显示/隐藏状态 try { - this.eap$showSlots = ModConfigs.PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT.get(); + this.eap$showSlots = ModConfig.INSTANCE.patternTerminalShowSlotsDefault; } catch (Throwable ignored) { } // 创建切换槽位显示的按钮 diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/common/PartExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/common/PartExPatternProviderMixin.java index d2077cf..306a560 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/common/PartExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/common/PartExPatternProviderMixin.java @@ -1,6 +1,6 @@ package com.extendedae_plus.mixin.extendedae.common; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.glodblock.github.extendedae.common.parts.PartExPatternProvider; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -18,7 +18,7 @@ public abstract class PartExPatternProviderMixin { index = 2 ) private int eap$multiplyCapacity(int original) { - int mult = ModConfigs.PAGE_MULTIPLIER.get(); + int mult = ModConfig.INSTANCE.pageMultiplier; if (mult < 1) mult = 1; if (mult > 64) mult = 64; return Math.max(1, original) * mult; diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/common/TileExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/common/TileExPatternProviderMixin.java index bb7ac07..b4f6fea 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/common/TileExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/common/TileExPatternProviderMixin.java @@ -1,6 +1,6 @@ package com.extendedae_plus.mixin.extendedae.common; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.glodblock.github.extendedae.common.tileentities.TileExPatternProvider; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -18,7 +18,7 @@ public abstract class TileExPatternProviderMixin { index = 2 ) private int eap$multiplyCapacity(int original) { - int mult = ModConfigs.PAGE_MULTIPLIER.get(); + int mult = ModConfig.INSTANCE.pageMultiplier; if (mult < 1) mult = 1; if (mult > 64) mult = 64; return Math.max(1, original) * mult; diff --git a/src/main/java/com/extendedae_plus/util/PatternScaler.java b/src/main/java/com/extendedae_plus/util/PatternScaler.java index 12acabd..11a454f 100644 --- a/src/main/java/com/extendedae_plus/util/PatternScaler.java +++ b/src/main/java/com/extendedae_plus/util/PatternScaler.java @@ -4,7 +4,7 @@ import appeng.api.stacks.AEKey; import appeng.api.stacks.GenericStack; import appeng.crafting.pattern.AEProcessingPattern; import com.extendedae_plus.api.SmartDoublingAwarePattern; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.content.ScaledProcessingPattern; public final class PatternScaler { @@ -56,7 +56,7 @@ public final class PatternScaler { } // 小请求绕过:若请求量小且不会带来收益,则不启用缩放(返回 null) try { - int minBenefit = ModConfigs.SMART_SCALING_MIN_BENEFIT_FACTOR.get(); + int minBenefit = ModConfig.INSTANCE.smartScalingMinBenefitFactor; if (minBenefit > 1 && requestedAmount > 0 && requestedAmount < perOperationTarget * (long) minBenefit) { return null; } @@ -65,7 +65,7 @@ public final class PatternScaler { } // 应用配置的最大倍数上限(0 表示不限制) try { - int maxMul = ModConfigs.SMART_SCALING_MAX_MULTIPLIER.get(); + int maxMul = ModConfig.INSTANCE.smartScalingMaxMultiplier; if (maxMul > 0 && multiplier > maxMul) { multiplier = maxMul; } diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java index 18219e0..93c5001 100644 --- a/src/main/java/com/extendedae_plus/util/PowerUtils.java +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -1,7 +1,7 @@ package com.extendedae_plus.util; import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; /** * 用于计算实体加速器的能耗与加速倍率的工具类 @@ -90,7 +90,7 @@ public final class PowerUtils { */ public static double computeFinalPowerForProduct(long product, int energyCardCount) { if (product <= 1L) return 0.0; - double base = ModConfigs.EntitySpeedTickerCost.get(); + double base = ModConfig.INSTANCE.entityTickerCost; // 计算以2为底的对数(用于分档与公式) double log2 = Math.log(product) / Math.log(2.0); @@ -121,7 +121,7 @@ public final class PowerUtils { } public static double getRawPower(int speedCardCount) { - double base = ModConfigs.EntitySpeedTickerCost.get(); + double base = ModConfig.INSTANCE.entityTickerCost; return base * getGrowthFactor(speedCardCount); } diff --git a/src/main/java/com/extendedae_plus/wireless/WirelessMasterRegistry.java b/src/main/java/com/extendedae_plus/wireless/WirelessMasterRegistry.java index 408bab0..a5f35b8 100644 --- a/src/main/java/com/extendedae_plus/wireless/WirelessMasterRegistry.java +++ b/src/main/java/com/extendedae_plus/wireless/WirelessMasterRegistry.java @@ -1,6 +1,6 @@ package com.extendedae_plus.wireless; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; @@ -63,7 +63,7 @@ public final class WirelessMasterRegistry { } private static boolean useGlobal() { - return ModConfigs.WIRELESS_CROSS_DIM_ENABLE.get(); + return ModConfig.INSTANCE.wirelessCrossDimEnable; } private record Key(ResourceKey dim, long freq) { diff --git a/src/main/java/com/extendedae_plus/wireless/WirelessSlaveLink.java b/src/main/java/com/extendedae_plus/wireless/WirelessSlaveLink.java index cc8988a..84035fd 100644 --- a/src/main/java/com/extendedae_plus/wireless/WirelessSlaveLink.java +++ b/src/main/java/com/extendedae_plus/wireless/WirelessSlaveLink.java @@ -3,7 +3,7 @@ package com.extendedae_plus.wireless; import appeng.api.networking.GridHelper; import appeng.api.networking.IGridNode; import appeng.me.service.helpers.ConnectionWrapper; -import com.extendedae_plus.config.ModConfigs; +import com.extendedae_plus.config.ModConfig; import net.minecraft.server.level.ServerLevel; import java.util.Objects; @@ -64,12 +64,12 @@ public class WirelessSlaveLink { shutdown = false; distance = 0.0D; - boolean crossDim = ModConfigs.WIRELESS_CROSS_DIM_ENABLE.get(); + boolean crossDim = ModConfig.INSTANCE.wirelessCrossDimEnable; if (master != null && !master.isEndpointRemoved() && (crossDim || master.getServerLevel() == level)) { if (!crossDim) { distance = Math.sqrt(master.getBlockPos().distSqr(host.getBlockPos())); } - double maxRange = ModConfigs.WIRELESS_MAX_RANGE.get(); + double maxRange = ModConfig.INSTANCE.wirelessMaxRange; if (crossDim || distance <= maxRange) { // 保持/建立连接 try { diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 561e56c..f2cee26 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -64,19 +64,21 @@ "extendedae_plus.tooltip.master_mode": "Mode: %s", "extendedae_plus.tooltip.locked": "Locked: %s", - "screen.extendedae_plus.title": "ExtendedAE Plus Config", - - "config.extendedae_plus.pageMultiplier": "Pattern Provider Page Multiplier", - "config.extendedae_plus.pageMultiplier_with_range": "Pattern Provider Page Multiplier (1-64)", - "config.extendedae_plus.wirelessMaxRange": "Wireless Max Range", - "config.extendedae_plus.wirelessMaxRange_with_range": "Wireless Max Range (1-4096)", - "config.extendedae_plus.wirelessCrossDimEnable": "Allow Wireless Cross-Dimension", - "config.extendedae_plus.providerRoundRobinEnable": "Enable Provider Round-Robin (Smart Doubling)", - "config.extendedae_plus.state_on": "On", - "config.extendedae_plus.state_off": "Off", - "config.extendedae_plus.showEncoderPatternPlayer": "Show Encoded Pattern Player", - "config.extendedae_plus.patternTerminalShowSlotsDefault": "Pattern Terminal Show Slots By Default", - "config.extendedae_plus.smartScalingMaxMultiplier": "Smart Scaling Max Multiplier", - "config.extendedae_plus.smartScalingMaxMultiplier_with_range": "Smart Scaling Max Multiplier (0 = Unlimited)", - "config.extendedae_plus.smartScalingMinBenefitFactor": "Smart Scaling Min Benefit Factor (default 4)" + "config.screen.extendedae_plus": "ExtendedAE Plus Config", + "config.extendedae_plus.option.pageMultiplier": "Pattern Provider Page Multiplier", + "config.extendedae_plus.option.pageMultiplier_with_range": "Pattern Provider Page Multiplier", + "config.extendedae_plus.option.wirelessMaxRange": "Wireless Max Range", + "config.extendedae_plus.option.wirelessMaxRange_with_range": "Wireless Max Range", + "config.extendedae_plus.option.wirelessCrossDimEnable": "Allow Wireless Cross-Dimension", + "config.extendedae_plus.option.providerRoundRobinEnable": "Enable Provider Round-Robin (Smart Doubling)", + "config.extendedae_plus.option.state_on": "On", + "config.extendedae_plus.option.state_off": "Off", + "config.extendedae_plus.option.showEncoderPatternPlayer": "Show Encoded Pattern Player", + "config.extendedae_plus.option.patternTerminalShowSlotsDefault": "Pattern Terminal Show Slots By Default", + "config.extendedae_plus.option.smartScalingMaxMultiplier": "Smart Scaling Max Multiplier", + "config.extendedae_plus.option.smartScalingMaxMultiplier_with_range": "Smart Scaling Max Multiplier", + "config.extendedae_plus.option.smartScalingMinBenefitFactor": "Smart Scaling Min Benefit Factor", + "config.extendedae_plus.option.entityTickerCost": "Entity Ticker Base Energy Cost", + "config.extendedae_plus.option.entityTickerBlackList": "Entity Ticker Blacklist", + "config.extendedae_plus.option.entityTickerMultipliers": "Entity Ticker Extra Consumption Multipliers" } \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 8a98475..177bf6d 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -64,19 +64,21 @@ "extendedae_plus.tooltip.master_mode": "模式: %s", "extendedae_plus.tooltip.locked": "锁定状态: %s", - "screen.extendedae_plus.title": "ExtendedAE Plus 配置", - - "config.extendedae_plus.pageMultiplier": "扩展样板供应器槽位倍率", - "config.extendedae_plus.pageMultiplier_with_range": "扩展样板供应器槽位倍率 (1-64)", - "config.extendedae_plus.wirelessMaxRange": "无线最大距离", - "config.extendedae_plus.wirelessMaxRange_with_range": "无线最大距离 (1-4096)", - "config.extendedae_plus.wirelessCrossDimEnable": "无线收发器允许跨维度连接", - "config.extendedae_plus.providerRoundRobinEnable": "启用样板供应器轮询分配(智能翻倍)", - "config.extendedae_plus.state_on": "开", - "config.extendedae_plus.state_off": "关", - "config.extendedae_plus.showEncoderPatternPlayer": "显示样板编码玩家", - "config.extendedae_plus.patternTerminalShowSlotsDefault": "样板终端默认显示槽位", - "config.extendedae_plus.smartScalingMaxMultiplier": "智能倍增最大倍数", - "config.extendedae_plus.smartScalingMaxMultiplier_with_range": "智能倍增最大倍数 (0为不限制)", - "config.extendedae_plus.smartScalingMinBenefitFactor": "智能倍增最小收益因子 (默认 4)" + "config.screen.extendedae_plus": "ExtendedAE Plus 配置", + "config.extendedae_plus.option.pageMultiplier": "扩展样板供应器槽位倍率", + "config.extendedae_plus.option.pageMultiplier_with_range": "扩展样板供应器槽位倍率", + "config.extendedae_plus.option.wirelessMaxRange": "无线最大距离", + "config.extendedae_plus.option.wirelessMaxRange_with_range": "无线最大距离", + "config.extendedae_plus.option.wirelessCrossDimEnable": "无线收发器允许跨维度连接", + "config.extendedae_plus.option.providerRoundRobinEnable": "启用样板供应器轮询分配(智能翻倍)", + "config.extendedae_plus.option.state_on": "开", + "config.extendedae_plus.option.state_off": "关", + "config.extendedae_plus.option.showEncoderPatternPlayer": "显示样板编码玩家", + "config.extendedae_plus.option.patternTerminalShowSlotsDefault": "样板终端默认显示槽位", + "config.extendedae_plus.option.smartScalingMaxMultiplier": "智能倍增最大倍数", + "config.extendedae_plus.option.smartScalingMaxMultiplier_with_range": "智能倍增最大倍数", + "config.extendedae_plus.option.smartScalingMinBenefitFactor": "智能倍增最小收益因子", + "config.extendedae_plus.option.entityTickerCost": "实体加速器能量消耗基础值", + "config.extendedae_plus.option.entityTickerBlackList": "实体加速器黑名单", + "config.extendedae_plus.option.entityTickerMultipliers": "实体加速器额外消耗倍率" } \ No newline at end of file diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index 5037016..af79b32 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -30,6 +30,7 @@ ], "mixins": [ "ae2.AEProcessingPatternMixin", + "ae2.CraftingCalculationMixin", "ae2.CraftingCPUClusterMixin", "ae2.EncodedPatternItemMixin", "ae2.accessor.MEStorageMenuAccessor", From 93d008113267ea1aa339bfa2346487b14611552c Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 15 Sep 2025 01:10:46 +0800 Subject: [PATCH 23/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E5=AE=9E=E4=BD=93=E5=8A=A0=E9=80=9F=E5=99=A8=E7=95=8C?= =?UTF-8?q?=E9=9D=A2=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../extendedae_plus/ae/client/gui/Icon.java | 33 +++++++++++++ .../ae/menu/EntitySpeedTickerMenu.java | 25 +++++++++- .../ae/screen/EntitySpeedTickerScreen.java | 46 ++++++++++++++++++- .../ae2/screens/entity_speed_ticker.json | 7 +++ .../assets/extendedae_plus/lang/en_us.json | 1 + .../assets/extendedae_plus/lang/zh_cn.json | 1 + .../models/item/entity_speed_card_x1.json | 6 --- .../models/item/entity_speed_ticker.json | 3 +- 8 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/ae/client/gui/Icon.java delete mode 100644 src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json diff --git a/src/main/java/com/extendedae_plus/ae/client/gui/Icon.java b/src/main/java/com/extendedae_plus/ae/client/gui/Icon.java new file mode 100644 index 0000000..9574df3 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/client/gui/Icon.java @@ -0,0 +1,33 @@ +package com.extendedae_plus.ae.client.gui; + +import appeng.client.gui.style.Blitter; +import com.extendedae_plus.ExtendedAEPlus; +import net.minecraft.resources.ResourceLocation; + +public enum Icon { + REDSTONE_LOW(0, 0), + REDSTONE_HIGH(16, 0); + + public final int x; + public final int y; + public final int width; + public final int height; + public static final ResourceLocation TEXTURE = new ResourceLocation(ExtendedAEPlus.MODID, "textures/guis/states.png"); + public static final int TEXTURE_WIDTH = 256; + public static final int TEXTURE_HEIGHT = 256; + + private Icon(int x, int y) { + this(x, y, 16, 16); + } + + private Icon(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public Blitter getBlitter() { + return Blitter.texture(TEXTURE, TEXTURE_WIDTH, TEXTURE_HEIGHT).src(this.x, this.y, this.width, this.height); + } +} diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index 2981e98..fcc6e5d 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -29,6 +29,7 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu extends Up ) { @Override public List getTooltipMessage() { + // 如果目标在黑名单中,直接显示已禁用的提示 + try { + if (menu != null && menu.targetBlacklisted) { + var title = Component.literal("实体加速"); + var stateLine = Component.literal("已禁用(目标在黑名单)"); + return List.of(title, stateLine); + } + } catch (Exception ignored) {} + boolean enabled = eap$entitySpeedTickerEnabled; var title = Component.literal("实体加速"); var stateLine = enabled @@ -48,6 +58,23 @@ public class EntitySpeedTickerScreen extends Up : Component.literal("已关闭: 不会对目标方块实体进行加速"); return List.of(title, stateLine); } + + @Override + protected Icon getIcon() { + try { + if (menu != null && menu.targetBlacklisted) { + // 黑名单时显示禁用图标 + return Icon.INVALID; + } + } catch (Exception ignored) {} + + // 根据当前值显示不同图标(可按需替换 Icon 常量) + if (this.getCurrentValue() == YesNo.YES) { + return Icon.VALID; + } else { + return Icon.INVALID; + } + } }; // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 eap$entitySpeedTickerToggle.set(this.eap$entitySpeedTickerEnabled ? YesNo.YES : YesNo.NO); @@ -66,7 +93,14 @@ public class EntitySpeedTickerScreen extends Up } this.eap$entitySpeedTickerEnabled = desired; - this.eap$entitySpeedTickerToggle.set(desired ? YesNo.YES : YesNo.NO); + // 如果目标在黑名单中,禁用切换并强制显示为关闭 + if (this.menu != null && this.menu.targetBlacklisted) { + this.eap$entitySpeedTickerToggle.set(YesNo.NO); + this.eap$entitySpeedTickerToggle.active = false; + } else { + this.eap$entitySpeedTickerToggle.set(desired ? YesNo.YES : YesNo.NO); + this.eap$entitySpeedTickerToggle.active = true; + } } textData(); } @@ -76,6 +110,16 @@ public class EntitySpeedTickerScreen extends Up } private void textData() { + // 如果目标被黑名单禁止,则显示禁用状态并把数值显示为 0 + if (getMenu().targetBlacklisted) { + setTextContent("enable", Component.translatable("screen.extendedae_plus.entity_speed_ticker.enable")); + setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", 0)); + setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(0.0, false))); + setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(0.0))); + setTextContent("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", 0.0))); + return; + } + int energyCardCount = getMenu().energyCardCount; double multiplier = getMenu().multiplier; int effectiveSpeed = getMenu().effectiveSpeed; diff --git a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json index 7654c5e..e30da1a 100644 --- a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json +++ b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json @@ -23,6 +23,13 @@ "top": 6 } }, + "enable": { + "position": { + "top": 20, + "left": 88 + }, + "align": "CENTER" + }, "speed": { "position": { "top": 35, diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index f2cee26..fb6c9f3 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -45,6 +45,7 @@ "extendedae_plus.pattern.hovertext.player": "Encoded by %s", "item.extendedae_plus.entity_speed_ticker": "Entity Speed Ticker", + "screen.extendedae_plus.entity_speed_ticker.enable": "§c§lThe machine has been disabled", "screen.extendedae_plus.entity_speed_ticker.energy": "Energy Usage: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power ratio: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 177bf6d..0347d13 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -45,6 +45,7 @@ "extendedae_plus.pattern.hovertext.player": "由 %s 编码", "item.extendedae_plus.entity_speed_ticker": "实体加速器", + "screen.extendedae_plus.entity_speed_ticker.enable": "§c§l机器已被禁用", "screen.extendedae_plus.entity_speed_ticker.energy": "能耗: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "功耗比例: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d", diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json deleted file mode 100644 index 1107187..0000000 --- a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_card_x1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "parent": "item/generated", - "textures": { "layer0": "extendedae_plus:item/entity_speed_card_x2" } -} - - diff --git a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json index 43a1e58..51789c2 100644 --- a/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json +++ b/src/main/resources/assets/extendedae_plus/models/item/entity_speed_ticker.json @@ -1,6 +1,7 @@ { "parent": "ae2:item/cable_interface", "textures": { - "front": "extendedae_plus:part/entity_speed_ticker_font" + "front": "extendedae_plus:part/entity_speed_ticker_font", + "back": "extendedae_plus:part/entity_speed_ticker_back" } } \ No newline at end of file From 857fadc7ad22b3a42de8ac98fdd749581cd045ec Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 15 Sep 2025 01:20:41 +0800 Subject: [PATCH 24/44] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E9=85=8D?= =?UTF-8?q?=E7=BD=AEAE=E5=90=88=E6=88=90=E6=9A=82=E5=81=9C=E6=A3=80?= =?UTF-8?q?=E6=9F=A5=E9=98=88=E5=80=BC=E4=BB=A5=E9=99=8D=E4=BD=8E=E4=B8=8A?= =?UTF-8?q?=E4=B8=8B=E6=96=87=E5=88=87=E6=8D=A2=E9=A2=91=E7=8E=87=EF=BC=8C?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E5=80=BC=20100000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/config/ModConfig.java | 8 +++++++ .../mixin/ae2/CraftingCalculationMixin.java | 21 +++++++++++++++++++ .../assets/extendedae_plus/lang/en_us.json | 3 ++- .../assets/extendedae_plus/lang/zh_cn.json | 3 ++- 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/mixin/ae2/CraftingCalculationMixin.java diff --git a/src/main/java/com/extendedae_plus/config/ModConfig.java b/src/main/java/com/extendedae_plus/config/ModConfig.java index 2a5bd63..413c54b 100644 --- a/src/main/java/com/extendedae_plus/config/ModConfig.java +++ b/src/main/java/com/extendedae_plus/config/ModConfig.java @@ -117,4 +117,12 @@ public final class ModConfig { }; + @Configurable + @Configurable.Comment(value = { + "值越大将减少AE构建合成计划过程中的 wait/notify 次数,提升吞吐但会降低调度响应性" + }) + @Configurable.Synchronized + @Configurable.Range(min = 100, max = Integer.MAX_VALUE) + public int craftingPauseThreshold = 100000; + } \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/CraftingCalculationMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/CraftingCalculationMixin.java new file mode 100644 index 0000000..1936c79 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/ae2/CraftingCalculationMixin.java @@ -0,0 +1,21 @@ +package com.extendedae_plus.mixin.ae2; + +import appeng.crafting.CraftingCalculation; +import com.extendedae_plus.config.ModConfig; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +/** + * Mixin 用于增加 CraftingCalculation.handlePausing() 中 incTime 的阈值。 + * 调整 CRAFTING_PAUSE_THRESHOLD 可以控制计算让出控制权的频率。 + */ +@Mixin(value = CraftingCalculation.class, remap = false) +public abstract class CraftingCalculationMixin { + // 可调节的阈值:在执行 pause 检查前 handlePausing 被调用的次数。 + // 增大此值可以减少 wait/notify 的频率(提升吞吐量但降低响应速度)。 + @ModifyConstant(method = "handlePausing", constant = @Constant(intValue = 100)) + private int modifyIncTimeThreshold(int original) { + return ModConfig.INSTANCE.craftingPauseThreshold; + } +} \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index fb6c9f3..230dade 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -81,5 +81,6 @@ "config.extendedae_plus.option.smartScalingMinBenefitFactor": "Smart Scaling Min Benefit Factor", "config.extendedae_plus.option.entityTickerCost": "Entity Ticker Base Energy Cost", "config.extendedae_plus.option.entityTickerBlackList": "Entity Ticker Blacklist", - "config.extendedae_plus.option.entityTickerMultipliers": "Entity Ticker Extra Consumption Multipliers" + "config.extendedae_plus.option.entityTickerMultipliers": "Entity Ticker Extra Consumption Multipliers", + "config.extendedae_plus.option.craftingPauseThreshold": "AE synthesis calculation pause check threshold" } \ No newline at end of file diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 0347d13..dd25863 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -81,5 +81,6 @@ "config.extendedae_plus.option.smartScalingMinBenefitFactor": "智能倍增最小收益因子", "config.extendedae_plus.option.entityTickerCost": "实体加速器能量消耗基础值", "config.extendedae_plus.option.entityTickerBlackList": "实体加速器黑名单", - "config.extendedae_plus.option.entityTickerMultipliers": "实体加速器额外消耗倍率" + "config.extendedae_plus.option.entityTickerMultipliers": "实体加速器额外消耗倍率", + "config.extendedae_plus.option.craftingPauseThreshold": "AE合成计算暂停检查阈值" } \ No newline at end of file From 6f42b50ea0ee3719834c1be5dfe05a3e89b23bd7 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 15 Sep 2025 09:50:51 +0800 Subject: [PATCH 25/44] =?UTF-8?q?feat:=20=E6=94=BE=E5=AE=BD=E6=89=A9?= =?UTF-8?q?=E5=B1=95=E4=BE=9B=E5=BA=94=E5=99=A8=E5=86=85=E7=9A=84=E6=A0=B7?= =?UTF-8?q?=E6=9D=BF=E6=89=8B=E5=8A=A8=E5=80=8D=E5=A2=9E=E9=99=90=E5=88=B6?= =?UTF-8?q?(=E4=B8=8D=E8=B6=85int),=20=E8=B0=83=E6=95=B4=E6=A0=B7=E6=9D=BF?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=EF=BC=8C=E4=BB=A5=E6=94=AF=E6=8C=81=E5=A4=A7?= =?UTF-8?q?=E6=95=B0=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ContainerExPatternProviderMixin.java | 19 +++++-- .../util/NumberFormatUtil.java | 51 ++++++++++++------- 2 files changed, 49 insertions(+), 21 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerExPatternProviderMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerExPatternProviderMixin.java index 94fe85a..3b09bf8 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerExPatternProviderMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerExPatternProviderMixin.java @@ -134,10 +134,12 @@ public abstract class ContainerExPatternProviderMixin extends PatternProviderMen } else { for (var stack : stacks) { if (stack != null) { - long upper = 999999L * stack.what().getAmountPerUnit(); - if (stack.amount() * scale > upper) { + long amt = stack.amount(); + // 先检查乘法是否会导致超出 Long.MAX_VALUE,避免溢出 + if (amt > Integer.MAX_VALUE / scale) { return false; } + // 已移除原有的业务上限检查(999999 * amountPerUnit),仅保留溢出检查 } } return true; @@ -150,7 +152,18 @@ public abstract class ContainerExPatternProviderMixin extends PatternProviderMen var stack = src[i]; if (stack != null) { long amt = stack.amount(); - long newAmt = div ? (amt / scale) : (amt * scale); + long newAmt; + if (div) { + newAmt = amt / scale; + } else { + // 防御性检查:虽然上游已检查过,但在此处再次确保不会溢出 + if (amt > Integer.MAX_VALUE / scale) { + // 遇到潜在溢出时跳过该项(保持原样为 null),调用方已通过 eap$checkModify 避免进入此分支 + dst[i] = null; + continue; + } + newAmt = amt * scale; + } dst[i] = new GenericStack(stack.what(), newAmt); } else { dst[i] = null; diff --git a/src/main/java/com/extendedae_plus/util/NumberFormatUtil.java b/src/main/java/com/extendedae_plus/util/NumberFormatUtil.java index 760b7be..b98d30d 100644 --- a/src/main/java/com/extendedae_plus/util/NumberFormatUtil.java +++ b/src/main/java/com/extendedae_plus/util/NumberFormatUtil.java @@ -1,5 +1,7 @@ package com.extendedae_plus.util; +import java.text.DecimalFormat; + /** * 数字格式化工具类,提供大数字和小数的格式化功能 */ @@ -7,46 +9,59 @@ public class NumberFormatUtil { private NumberFormatUtil() {throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");} /** - * 格式化数字,将大数字转换为k、m等格式 - * 支持小数显示,小数点后为0则不显示0 + * 格式化数字,将大数字转换为 k、M、G 等格式(物品用整数/一位小数显示规则) * @param number 要格式化的数字 * @return 格式化后的字符串 */ public static String formatNumber(long number) { if (number < 1000) { return String.valueOf(number); - } else if (number < 1000000) { - double value = number / 1000.0; - return formatDecimal(value, "k"); - } else { - double value = number / 1000000.0; - return formatDecimal(value, "m"); } + + String[] preFixes = new String[]{"k", "M", "G", "T", "P", "E", "Z", "Y"}; + double value = number; + String level = ""; + + for (int offset = 0; value >= 1000.0 && offset < preFixes.length; ++offset) { + value /= 1000.0; + level = preFixes[offset]; + } + + return formatDecimal(value, level); } /** - * 格式化带小数的数字,支持流体等需要显示小数的场景 + * 格式化带小数的数字,支持流体等需要显示小数的场景(保留至多两位小数) + * 流体显示规则不同于物品,统一使用两位小数的 DecimalFormat * @param value 小数值 * @return 格式化后的字符串 */ public static String formatNumberWithDecimal(double value) { if (value < 1000) { + DecimalFormat smallDf = new DecimalFormat("#.##"); + // 小于1000时,若是整数则显示整数,否则显示最多两位小数 if (value == (long) value) { return String.valueOf((long) value); } else { - return String.format("%.1f", value).replaceAll("\\.0$", ""); + return smallDf.format(value); } - } else if (value < 1000000) { - return formatDecimal(value / 1000.0, "k"); - } else { - return formatDecimal(value / 1000000.0, "m"); } + + String[] preFixes = new String[]{"k", "M", "G", "T", "P", "E", "Z", "Y"}; + String level = ""; + for (int offset = 0; value >= 1000.0 && offset < preFixes.length; ++offset) { + value /= 1000.0; + level = preFixes[offset]; + } + + DecimalFormat df = new DecimalFormat("#.##"); + return df.format(value) + level; } /** - * 格式化小数,如果小数点后为0则不显示0 + * 格式化小数(物品显示规则):如果小数点后接近 0 则显示为整数,否则显示一位小数 * @param value 小数值 - * @param suffix 后缀(k、m、g等) + * @param suffix 后缀(k、M、G 等) * @return 格式化后的字符串 */ private static String formatDecimal(double value, String suffix) { @@ -54,9 +69,9 @@ public class NumberFormatUtil { if (Math.abs(value - Math.round(value)) < 0.001) { return String.valueOf(Math.round(value)) + suffix; } else { - // 修复重复后缀问题:先格式化数字,再添加后缀 + // 使用一位小数显示,去掉末尾 .0 String formatted = String.format("%.1f", value).replaceAll("\\.0$", ""); return formatted + suffix; } } -} \ No newline at end of file +} \ No newline at end of file From 9f98768ee28c87f642d1d17306281e0f5ae2a080 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 15 Sep 2025 12:39:30 +0800 Subject: [PATCH 26/44] =?UTF-8?q?feat:=20=E6=99=BA=E8=83=BD=E9=98=BB?= =?UTF-8?q?=E6=8C=A1=E5=BC=80=E5=90=AF=E7=9A=84=E6=97=B6=E5=80=99=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=BC=80=E5=90=AF=E5=8E=9F=E7=89=88=E9=98=BB=E6=8C=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../network/ToggleAdvancedBlockingC2SPacket.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java b/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java index 74bfdea..f58f500 100644 --- a/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java @@ -1,5 +1,7 @@ package com.extendedae_plus.network; +import appeng.api.config.Settings; +import appeng.api.config.YesNo; import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; @@ -36,6 +38,8 @@ public class ToggleAdvancedBlockingC2SPacket { boolean current = holder.eap$getAdvancedBlocking(); boolean next = !current; holder.eap$setAdvancedBlocking(next); + // 自动开启原版阻挡 + logic.getConfigManager().putSetting(Settings.BLOCKING_MODE, YesNo.YES); // 保存并触发 AE2 的菜单 @GuiSync 广播到所有观看该菜单的玩家 logic.saveChanges(); } From fa37427ddaea58129eb1e078192544f1f3a3b18b Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 15 Sep 2025 14:50:22 +0800 Subject: [PATCH 27/44] =?UTF-8?q?feat:=20=E8=B0=83=E6=95=B4=E6=97=A0?= =?UTF-8?q?=E7=BA=BF=E6=94=B6=E5=8F=91=E5=99=A8=E7=BB=A7=E6=89=BFAEBaseBlo?= =?UTF-8?q?ckEntity=E4=BB=A5=E6=94=AF=E6=8C=81ae=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E9=87=8D=E5=91=BD=E5=90=8D=E5=8A=9F=E8=83=BD;=20=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0jade=E4=BB=8E=E8=8A=82=E7=82=B9=E6=96=B9=E5=9D=97?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=B8=BB=E8=8A=82=E7=82=B9=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wireless/WirelessTransceiverBlockEntity.java | 12 ++++++------ .../WirelessTransceiverJadePluginComponents.java | 7 ++++++- .../jade/WirelessTransceiverProvider.java | 3 +++ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java b/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java index 9b2830e..09b843d 100644 --- a/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java +++ b/src/main/java/com/extendedae_plus/content/wireless/WirelessTransceiverBlockEntity.java @@ -2,6 +2,7 @@ package com.extendedae_plus.content.wireless; import appeng.api.networking.*; import appeng.api.util.AECableType; +import appeng.blockentity.AEBaseBlockEntity; import com.extendedae_plus.init.ModBlockEntities; import com.extendedae_plus.init.ModItems; import com.extendedae_plus.wireless.IWirelessEndpoint; @@ -12,7 +13,6 @@ import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; @@ -26,7 +26,7 @@ import java.util.Objects; * - 集成 AE2 节点; * - 集成无线主/从逻辑。 */ -public class WirelessTransceiverBlockEntity extends BlockEntity implements IWirelessEndpoint, IInWorldGridNodeHost { +public class WirelessTransceiverBlockEntity extends AEBaseBlockEntity implements IWirelessEndpoint, IInWorldGridNodeHost { private IManagedGridNode managedNode; @@ -187,7 +187,7 @@ public class WirelessTransceiverBlockEntity extends BlockEntity implements IWire /* ===================== NBT ===================== */ @Override - protected void saveAdditional(CompoundTag tag) { + public void saveAdditional(CompoundTag tag) { super.saveAdditional(tag); tag.putLong("frequency", frequency); tag.putBoolean("master", masterMode); @@ -198,15 +198,15 @@ public class WirelessTransceiverBlockEntity extends BlockEntity implements IWire } @Override - public void load(CompoundTag tag) { - super.load(tag); + public void loadTag(CompoundTag tag) { + super.loadTag(tag); this.frequency = tag.getLong("frequency"); this.masterMode = tag.getBoolean("master"); this.locked = tag.getBoolean("locked"); + if (managedNode != null) { managedNode.loadFromNBT(tag); } - // 应用到链接器 if (masterMode) { masterLink.setFrequency(frequency); } else { diff --git a/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverJadePluginComponents.java b/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverJadePluginComponents.java index 4cd98a9..2505db5 100644 --- a/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverJadePluginComponents.java +++ b/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverJadePluginComponents.java @@ -37,7 +37,12 @@ public enum WirelessTransceiverJadePluginComponents implements IBlockComponentPr if (data.contains("masterMode") && !data.getBoolean("masterMode") && data.contains("masterPos")) { BlockPos pos = BlockPos.of(data.getLong("masterPos")); String dim = data.contains("masterDim") ? data.getString("masterDim") : ""; - tooltip.add(Component.literal("主节点位置: (" + pos.getX() + ", " + pos.getY() + ", " + pos.getZ() + ")")); + String customName = data.contains("customName") ? data.getString("customName") : null; + if (customName != null) { + tooltip.add(Component.literal("主节点: " + customName + "(" + pos.getX() + ", " + pos.getY() + ", " + pos.getZ() + ")")); + } else { + tooltip.add(Component.literal("主节点位置: (" + pos.getX() + ", " + pos.getY() + ", " + pos.getZ() + ")")); + } if (!dim.isEmpty()) { tooltip.add(Component.literal("维度: " + dim)); } diff --git a/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverProvider.java b/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverProvider.java index 05e34a8..7786e1c 100644 --- a/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverProvider.java +++ b/src/main/java/com/extendedae_plus/integration/jade/WirelessTransceiverProvider.java @@ -46,6 +46,9 @@ public enum WirelessTransceiverProvider implements IServerDataProvider Date: Mon, 15 Sep 2025 18:06:49 +0800 Subject: [PATCH 28/44] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=99=BA?= =?UTF-8?q?=E8=83=BD=E7=B3=BB=E5=88=97=E5=AF=B9=E9=AB=98=E7=BA=A7ae?= =?UTF-8?q?=E4=BE=9B=E5=BA=94=E5=99=A8=E7=9A=84=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ernProviderLogicContainsRedirectMixin.java | 38 +++++ ...vPatternProviderLogicPatternsAccessor.java | 14 ++ ...dvPatternProviderMenuAdvancedAccessor.java | 12 ++ .../gui/AdvPatternProviderScreenMixin.java | 147 ++++++++++++++++++ .../SmallAdvPatternProviderScreenMixin.java | 147 ++++++++++++++++++ .../AdvPatternProviderLogicAdvancedMixin.java | 109 +++++++++++++ .../AdvPatternProviderLogicDoublingMixin.java | 91 +++++++++++ .../AdvPatternProviderMenuAdvancedMixin.java | 66 ++++++++ .../AdvPatternProviderMenuDoublingMixin.java | 62 ++++++++ .../gui/PatternProviderScreenMixin.java | 5 - .../PatternProviderLogicAdvancedMixin.java | 14 +- .../PatternProviderLogicDoublingMixin.java | 14 +- .../PatternProviderMenuAdvancedMixin.java | 15 +- .../PatternProviderMenuDoublingMixin.java | 1 - .../ToggleAdvancedBlockingC2SPacket.java | 39 +++-- .../network/ToggleSmartDoublingC2SPacket.java | 30 ++-- .../resources/extendedae_plus.mixins.json | 9 ++ 17 files changed, 758 insertions(+), 55 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/AdvPatternProviderLogicContainsRedirectMixin.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderLogicPatternsAccessor.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicAdvancedMixin.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java create mode 100644 src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/AdvPatternProviderLogicContainsRedirectMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/AdvPatternProviderLogicContainsRedirectMixin.java new file mode 100644 index 0000000..0773388 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/AdvPatternProviderLogicContainsRedirectMixin.java @@ -0,0 +1,38 @@ +package com.extendedae_plus.mixin.advancedae; + +import appeng.api.crafting.IPatternDetails; +import com.extendedae_plus.content.ScaledProcessingPattern; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +import java.util.List; + +/**适配 + * Redirect PatternProviderLogic.pushPattern 中对 List.contains 的调用, + * 在遇到缩放样板时回退匹配到原始样板实例。 + */ +@Mixin(value = AdvPatternProviderLogic.class, remap = false) +public class AdvPatternProviderLogicContainsRedirectMixin { + + @Redirect(method = "pushPattern", + at = @At( + value = "INVOKE", + target = "Ljava/util/List;contains(Ljava/lang/Object;)Z") + ) + private boolean eap$patternsContains(List list, Object o) { + try { + if (o instanceof ScaledProcessingPattern scaled) { + IPatternDetails base = scaled.getOriginal(); + if (base != null && list.indexOf(base) != -1) { + return true; + } + } + // 使用 indexOf 避免再次触发对 List.contains 的 redirect(防止递归) + return list.indexOf(o) != -1; + } catch (Throwable t) { + return list.indexOf(o) != -1; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderLogicPatternsAccessor.java b/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderLogicPatternsAccessor.java new file mode 100644 index 0000000..a75643c --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderLogicPatternsAccessor.java @@ -0,0 +1,14 @@ +package com.extendedae_plus.mixin.advancedae.accessor; + +import appeng.api.crafting.IPatternDetails; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(value = AdvPatternProviderLogic.class, remap = false) +public interface AdvPatternProviderLogicPatternsAccessor { + @Accessor("patterns") + List eap$patterns(); +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java b/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java new file mode 100644 index 0000000..bf6987e --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java @@ -0,0 +1,12 @@ +package com.extendedae_plus.mixin.advancedae.accessor; + +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(AdvPatternProviderMenu.class) +public interface AdvPatternProviderMenuAdvancedAccessor { + @Accessor("logic") + AdvPatternProviderLogic eap$logic(); +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java new file mode 100644 index 0000000..5cd6c30 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java @@ -0,0 +1,147 @@ +package com.extendedae_plus.mixin.advancedae.client.gui; + +import appeng.api.config.Settings; +import appeng.api.config.YesNo; +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.SettingToggleButton; +import com.extendedae_plus.api.ExPatternButtonsAccessor; +import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; +import com.extendedae_plus.api.PatternProviderMenuDoublingSync; +import com.extendedae_plus.init.ModNetwork; +import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; +import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket; +import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.pedroksl.advanced_ae.client.gui.AdvPatternProviderScreen; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; +import org.checkerframework.checker.units.qual.C; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; + +/** + * 为高级ae样板供应器界面添加“高级阻挡模式”按钮。 + * - 位于左侧工具栏 + * - 点击仅发送 C2S 切换请求;状态由 AE2 @GuiSync 回传决定 + */ +@Mixin(AdvPatternProviderScreen.class) +public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen { + + @Unique + private SettingToggleButton eap$AdvancedBlockingToggle; + + @Unique + private boolean eap$AdvancedBlockingEnabled = false; + + @Unique + private SettingToggleButton eap$SmartDoublingToggle; + + @Unique + private boolean eap$SmartDoublingEnabled = false; + + public AdvPatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) { + super((AdvPatternProviderMenu) menu, playerInventory, title, style); + } + + @Inject(method = "", at = @At("RETURN")) + private void eap$initAdvancedBlocking(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { + // 使用 @GuiSync 初始化 + try { + if (menu instanceof PatternProviderMenuAdvancedSync sync) { + this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); + } + } catch (Throwable t) { + LOGGER.error("Error initializing advanced sync", t); + } + + // 使用 SettingToggleButton 的外观(原版图标),但自定义悬停描述为“智能阻挡” + this.eap$AdvancedBlockingToggle = new SettingToggleButton<>( + Settings.BLOCKING_MODE, + this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO, + (btn, backwards) -> { + // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 + ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()); + } + ) { + @Override + public java.util.List getTooltipMessage() { + boolean enabled = eap$AdvancedBlockingEnabled; + var title = Component.literal("智能阻挡"); + var line = enabled + ? Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)") + : Component.literal("已禁用:这么好的功能为什么不打开呢"); + return java.util.List.of(title, line); + } + }; + // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 + this.eap$AdvancedBlockingToggle.set(this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); + + this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); + + // 智能翻倍按钮:与高级阻挡同款样式,点击仅发送C2S,状态由@GuiSync驱动 + try { + if (menu instanceof PatternProviderMenuDoublingSync sync2) { + this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); + } + } catch (Throwable t) { + LOGGER.error("Error initializing smart doubling sync", t); + } + + this.eap$SmartDoublingToggle = new SettingToggleButton<>( + Settings.BLOCKING_MODE, + this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO, + (btn, backwards) -> { + ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()); + } + ) { + @Override + public java.util.List getTooltipMessage() { + boolean enabled = eap$SmartDoublingEnabled; + var title = Component.literal("智能翻倍"); + var line = enabled + ? Component.literal("已启用:根据请求量对处理样板进行智能缩放") + : Component.literal("已禁用:按原始样板数量进行发配"); + return java.util.List.of(title, line); + } + }; + + this.eap$SmartDoublingToggle.set(this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); + this.addToLeftToolbar(this.eap$SmartDoublingToggle); + } + + // 每帧刷新:仅从菜单(@GuiSync)同步布尔值,保持按钮状态一致 + @Inject(method = "updateBeforeRender", at = @At("HEAD"), remap = false) + private void eap$updateAdvancedBlocking(CallbackInfo ci) { + if (this.eap$AdvancedBlockingToggle != null) { + boolean desired = this.eap$AdvancedBlockingEnabled; + if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { + desired = sync.eap$getAdvancedBlockingSynced(); + } + this.eap$AdvancedBlockingEnabled = desired; + this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); + } + + if (this.eap$SmartDoublingToggle != null) { + boolean desired2 = this.eap$SmartDoublingEnabled; + if (this.menu instanceof PatternProviderMenuDoublingSync sync2) { + desired2 = sync2.eap$getSmartDoublingSynced(); + } + this.eap$SmartDoublingEnabled = desired2; + this.eap$SmartDoublingToggle.set(desired2 ? YesNo.YES : YesNo.NO); + } + + if ((Object) this instanceof GuiExPatternProvider) { + try { + ((ExPatternButtonsAccessor) this).eap$updateButtonsLayout(); + } catch (Throwable t) { + LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString()); + } + } + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java new file mode 100644 index 0000000..106207f --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/SmallAdvPatternProviderScreenMixin.java @@ -0,0 +1,147 @@ +package com.extendedae_plus.mixin.advancedae.client.gui; + +import appeng.api.config.Settings; +import appeng.api.config.YesNo; +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.style.ScreenStyle; +import appeng.client.gui.widgets.SettingToggleButton; +import com.extendedae_plus.api.ExPatternButtonsAccessor; +import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; +import com.extendedae_plus.api.PatternProviderMenuDoublingSync; +import com.extendedae_plus.init.ModNetwork; +import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket; +import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket; +import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Inventory; +import net.pedroksl.advanced_ae.client.gui.SmallAdvPatternProviderScreen; +import net.pedroksl.advanced_ae.gui.advpatternprovider.SmallAdvPatternProviderMenu; +import org.checkerframework.checker.units.qual.C; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; + +/** + * 为高级ae样板供应器界面添加“高级阻挡模式”按钮。 + * - 位于左侧工具栏 + * - 点击仅发送 C2S 切换请求;状态由 AE2 @GuiSync 回传决定 + */ +@Mixin(SmallAdvPatternProviderScreen.class) +public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen { + + @Unique + private SettingToggleButton eap$AdvancedBlockingToggle; + + @Unique + private boolean eap$AdvancedBlockingEnabled = false; + + @Unique + private SettingToggleButton eap$SmartDoublingToggle; + + @Unique + private boolean eap$SmartDoublingEnabled = false; + + public SmallAdvPatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) { + super((SmallAdvPatternProviderMenu) menu, playerInventory, title, style); + } + + @Inject(method = "", at = @At("RETURN")) + private void eap$initAdvancedBlocking(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) { + // 使用 @GuiSync 初始化 + try { + if (menu instanceof PatternProviderMenuAdvancedSync sync) { + this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced(); + } + } catch (Throwable t) { + LOGGER.error("Error initializing advanced sync", t); + } + + // 使用 SettingToggleButton 的外观(原版图标),但自定义悬停描述为“智能阻挡” + this.eap$AdvancedBlockingToggle = new SettingToggleButton<>( + Settings.BLOCKING_MODE, + this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO, + (btn, backwards) -> { + // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 + ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()); + } + ) { + @Override + public java.util.List getTooltipMessage() { + boolean enabled = eap$AdvancedBlockingEnabled; + var title = Component.literal("智能阻挡"); + var line = enabled + ? Component.literal("已启用:对于同一种配方将不再阻挡(需要开启原版的阻挡模式)") + : Component.literal("已禁用:这么好的功能为什么不打开呢"); + return java.util.List.of(title, line); + } + }; + // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 + this.eap$AdvancedBlockingToggle.set(this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); + + this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); + + // 智能翻倍按钮:与高级阻挡同款样式,点击仅发送C2S,状态由@GuiSync驱动 + try { + if (menu instanceof PatternProviderMenuDoublingSync sync2) { + this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced(); + } + } catch (Throwable t) { + LOGGER.error("Error initializing smart doubling sync", t); + } + + this.eap$SmartDoublingToggle = new SettingToggleButton<>( + Settings.BLOCKING_MODE, + this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO, + (btn, backwards) -> { + ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()); + } + ) { + @Override + public java.util.List getTooltipMessage() { + boolean enabled = eap$SmartDoublingEnabled; + var title = Component.literal("智能翻倍"); + var line = enabled + ? Component.literal("已启用:根据请求量对处理样板进行智能缩放") + : Component.literal("已禁用:按原始样板数量进行发配"); + return java.util.List.of(title, line); + } + }; + + this.eap$SmartDoublingToggle.set(this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO); + this.addToLeftToolbar(this.eap$SmartDoublingToggle); + } + + // 每帧刷新:仅从菜单(@GuiSync)同步布尔值,保持按钮状态一致 + @Inject(method = "updateBeforeRender", at = @At("HEAD"), remap = false) + private void eap$updateAdvancedBlocking(CallbackInfo ci) { + if (this.eap$AdvancedBlockingToggle != null) { + boolean desired = this.eap$AdvancedBlockingEnabled; + if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { + desired = sync.eap$getAdvancedBlockingSynced(); + } + this.eap$AdvancedBlockingEnabled = desired; + this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); + } + + if (this.eap$SmartDoublingToggle != null) { + boolean desired2 = this.eap$SmartDoublingEnabled; + if (this.menu instanceof PatternProviderMenuDoublingSync sync2) { + desired2 = sync2.eap$getSmartDoublingSynced(); + } + this.eap$SmartDoublingEnabled = desired2; + this.eap$SmartDoublingToggle.set(desired2 ? YesNo.YES : YesNo.NO); + } + + if ((Object) this instanceof GuiExPatternProvider) { + try { + ((ExPatternButtonsAccessor) this).eap$updateButtonsLayout(); + } catch (Throwable t) { + LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString()); + } + } + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicAdvancedMixin.java new file mode 100644 index 0000000..8df0927 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicAdvancedMixin.java @@ -0,0 +1,109 @@ +package com.extendedae_plus.mixin.advancedae.helpers; + +import appeng.api.crafting.IPatternDetails; +import appeng.api.crafting.IPatternDetails.IInput; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.GenericStack; +import appeng.helpers.patternprovider.PatternProviderTarget; +import com.extendedae_plus.api.AdvancedBlockingHolder; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import java.util.Collections; + +@Mixin(value = AdvPatternProviderLogic.class, remap = false) +public class AdvPatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder { + @Unique + private static final String EAP_ADV_BLOCKING_KEY = "eap_advanced_blocking"; + + @Unique + private boolean eap$advancedBlocking = false; + + @Override + public boolean eap$getAdvancedBlocking() { + return eap$advancedBlocking; + } + + @Override + public void eap$setAdvancedBlocking(boolean value) { + this.eap$advancedBlocking = value; + } + + @Inject(method = "writeToNBT", at = @At("TAIL")) + private void eap$writeAdvancedToNbt(CompoundTag tag, CallbackInfo ci) { + tag.putBoolean(EAP_ADV_BLOCKING_KEY, this.eap$advancedBlocking); + } + + @Inject(method = "readFromNBT", at = @At("TAIL")) + private void eap$readAdvancedFromNbt(CompoundTag tag, CallbackInfo ci) { + if (tag.contains(EAP_ADV_BLOCKING_KEY)) { + this.eap$advancedBlocking = tag.getBoolean(EAP_ADV_BLOCKING_KEY); + } + } + + // 在 pushPattern 中,重定向对 adapter.containsPatternInput(...) 的调用 + @Redirect(method = "pushPattern", at = @At(value = "INVOKE", target = "Lappeng/helpers/patternprovider/PatternProviderTarget;containsPatternInput(Ljava/util/Set;)Z")) + private boolean eap$redirectBlockingContains(PatternProviderTarget adapter, + java.util.Set patternInputs, + IPatternDetails patternDetails, + appeng.api.stacks.KeyCounter[] inputHolder) { + // 原版是否打开阻挡 + boolean vanillaBlocking = ((AdvPatternProviderLogic)(Object)this).isBlocking(); + if (!vanillaBlocking) { + return adapter.containsPatternInput(patternInputs); + } + + // 仅当高级阻挡启用时启用“匹配则不阻挡” + if (this.eap$advancedBlocking) { + if (eap$targetFullyMatchesPatternInputs(adapter, patternDetails)) { + // 返回 false 表示“不包含阻挡关键物”,从而不触发 continue,允许发配 + return false; + } + } + // 否则使用原判定 + return adapter.containsPatternInput(patternInputs); + } + + @Unique + private boolean eap$targetFullyMatchesPatternInputs(PatternProviderTarget adapter, IPatternDetails patternDetails) { + for (IInput in : patternDetails.getInputs()) { + boolean slotMatched = false; + for (GenericStack candidate : in.getPossibleInputs()) { + AEKey key = candidate.what().dropSecondary(); + if (adapter.containsPatternInput(Collections.singleton(key))) { + slotMatched = true; + break; + } + } + if (!slotMatched) { + return false; // 任一输入槽未匹配则失败 + } + } + return true; // 每个输入槽都至少匹配了一个候选输入 + } + + @Shadow public void saveChanges() {} + + @Inject(method = "exportSettings(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("TAIL")) + private void onExportSettings(CompoundTag output, CallbackInfo ci) { + System.out.println(this.eap$advancedBlocking); + output.putBoolean(EAP_ADV_BLOCKING_KEY, this.eap$advancedBlocking); + } + + @Inject(method = "importSettings(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/entity/player/Player;)V", at = @At("TAIL")) + private void onImportSettings(CompoundTag input, Player player, CallbackInfo ci) { + if (input.contains(EAP_ADV_BLOCKING_KEY)) { + this.eap$advancedBlocking = input.getBoolean(EAP_ADV_BLOCKING_KEY); + // 持久化到 world + this.saveChanges(); + } + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java new file mode 100644 index 0000000..85f7041 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/helpers/AdvPatternProviderLogicDoublingMixin.java @@ -0,0 +1,91 @@ +package com.extendedae_plus.mixin.advancedae.helpers; + +import appeng.api.crafting.IPatternDetails; +import appeng.crafting.pattern.AEProcessingPattern; +import com.extendedae_plus.api.SmartDoublingAwarePattern; +import com.extendedae_plus.api.SmartDoublingHolder; +import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderLogicPatternsAccessor; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(value = AdvPatternProviderLogic.class, remap = false) +public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder { + @Unique + private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling"; + + @Unique + private boolean eap$smartDoubling = false; + + @Override + public boolean eap$getSmartDoubling() { + return eap$smartDoubling; + } + + @Override + public void eap$setSmartDoubling(boolean value) { + this.eap$smartDoubling = value; + // 立即将开关状态应用到当前 Provider 的样板上,避免等待下一次 updatePatterns + try { + var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns(); + for (IPatternDetails details : list) { + if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) { + aware.eap$setAllowScaling(value); + } + } + // 触发一次刷新,让网络及时拿到最新状态(也会触发 ICraftingProvider.requestUpdate(mainNode)) + ((AdvPatternProviderLogic) (Object) this).updatePatterns(); + } catch (Throwable ignored) { + } + } + + @Inject(method = "writeToNBT", at = @At("TAIL")) + private void eap$writeSmartDoublingToNbt(CompoundTag tag, CallbackInfo ci) { + tag.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); + } + + @Inject(method = "readFromNBT", at = @At("TAIL")) + private void eap$readSmartDoublingFromNbt(CompoundTag tag, CallbackInfo ci) { + if (tag.contains(EAP_SMART_DOUBLING_KEY)) { + this.eap$smartDoubling = tag.getBoolean(EAP_SMART_DOUBLING_KEY); + } + } + + @Inject(method = "updatePatterns", at = @At("TAIL")) + private void eap$applySmartDoublingToPatterns(CallbackInfo ci) { + try { + var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns(); + boolean allow = this.eap$smartDoubling; + for (IPatternDetails details : list) { + if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) { + aware.eap$setAllowScaling(allow); + } + } + } catch (Throwable ignored) { + } + } + + @Shadow + public void saveChanges() {} + + @Inject(method = "exportSettings(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("TAIL")) + private void onExportSettings(CompoundTag output, CallbackInfo ci) { + System.out.println(this.eap$smartDoubling); + output.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); + } + + @Inject(method = "importSettings(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/entity/player/Player;)V", at = @At("TAIL")) + private void onImportSettings(CompoundTag input, Player player, CallbackInfo ci) { + if (input.contains(EAP_SMART_DOUBLING_KEY)) { + this.eap$smartDoubling = input.getBoolean(EAP_SMART_DOUBLING_KEY); + // 持久化到 world + this.saveChanges(); + } + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java new file mode 100644 index 0000000..db4ae90 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java @@ -0,0 +1,66 @@ +package com.extendedae_plus.mixin.advancedae.menu; + +import appeng.menu.AEBaseMenu; +import appeng.menu.guisync.GuiSync; +import com.extendedae_plus.api.AdvancedBlockingHolder; +import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.MenuType; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogicHost; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(AdvPatternProviderMenu.class) +public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync { + @Shadow + protected AdvPatternProviderLogic logic; + + // 选择一个未占用的 GUI 同步 id(AE2 已用到 7),这里使用 21 以避冲突 + @Unique + @GuiSync(22) + public boolean eap$AdvancedBlocking = false; + + @Inject(method = "broadcastChanges", at = @At("HEAD")) + private void eap$syncAdvancedBlocking(CallbackInfo ci) { + // 避免@Shadow父类方法,改用公共API:AEBaseMenu#isClientSide() + if (!((AEBaseMenu) (Object) this).isClientSide()) { + var l = this.logic; + if (l instanceof AdvancedBlockingHolder holder) { + this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); + } + } + } + + // 构造器尾注入(public ctor) + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + private void eap$initAdvancedSync_Public(int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { + try { + var l = this.logic; + if (l instanceof AdvancedBlockingHolder holder) { + this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); + } + } catch (Throwable ignored) {} + } + + // 构造器尾注入(protected ctor with MenuType) + @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + private void eap$initAdvancedSync_Protected(MenuType menuType, int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { + try { + var l = this.logic; + if (l instanceof AdvancedBlockingHolder holder) { + this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); + } + } catch (Throwable ignored) {} + } + + @Override + public boolean eap$getAdvancedBlockingSynced() { + return this.eap$AdvancedBlocking; + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java new file mode 100644 index 0000000..7e63986 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java @@ -0,0 +1,62 @@ +package com.extendedae_plus.mixin.advancedae.menu; + +import appeng.menu.AEBaseMenu; +import appeng.menu.guisync.GuiSync; +import com.extendedae_plus.api.PatternProviderMenuDoublingSync; +import com.extendedae_plus.api.SmartDoublingHolder; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.MenuType; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; +import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogicHost; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(AdvPatternProviderMenu.class) +public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync { + @Shadow + protected AdvPatternProviderLogic logic; + + @Unique + @GuiSync(23) + public boolean eap$SmartDoubling = false; + + @Inject(method = "broadcastChanges", at = @At("HEAD")) + private void eap$syncSmartDoubling(CallbackInfo ci) { + if (!((AEBaseMenu) (Object) this).isClientSide()) { + var l = this.logic; + if (l instanceof SmartDoublingHolder holder) { + this.eap$SmartDoubling = holder.eap$getSmartDoubling(); + } + } + } + + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + private void eap$initSmartSync_Public(int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { + try { + var l = this.logic; + if (l instanceof SmartDoublingHolder holder) { + this.eap$SmartDoubling = holder.eap$getSmartDoubling(); + } + } catch (Throwable ignored) {} + } + + @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + private void eap$initSmartSync_Protected(MenuType menuType, int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { + try { + var l = this.logic; + if (l instanceof SmartDoublingHolder holder) { + this.eap$SmartDoubling = holder.eap$getSmartDoubling(); + } + } catch (Throwable ignored) {} + } + + @Override + public boolean eap$getSmartDoublingSynced() { + return this.eap$SmartDoubling; + } +} diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java index 2fb5edd..863fab3 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderScreenMixin.java @@ -65,7 +65,6 @@ public abstract class PatternProviderScreenMixin this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO, (btn, backwards) -> { // 不做本地切换,点击仅发送自定义C2S,显示由@GuiSync回传 - LOGGER.debug("[EAP] Click advanced blocking toggle: send C2S"); ModNetwork.CHANNEL.sendToServer(new ToggleAdvancedBlockingC2SPacket()); } ) { @@ -80,7 +79,6 @@ public abstract class PatternProviderScreenMixin } }; // 初始化后立刻对齐当前@GuiSync状态,避免首帧显示不一致 - LOGGER.debug("[EAP] Screen init: initial synced={} -> set button", this.eap$AdvancedBlockingEnabled); this.eap$AdvancedBlockingToggle.set(this.eap$AdvancedBlockingEnabled ? YesNo.YES : YesNo.NO); this.addToLeftToolbar(this.eap$AdvancedBlockingToggle); @@ -98,7 +96,6 @@ public abstract class PatternProviderScreenMixin Settings.BLOCKING_MODE, this.eap$SmartDoublingEnabled ? YesNo.YES : YesNo.NO, (btn, backwards) -> { - LOGGER.debug("[EAP] Click smart doubling toggle: send C2S"); ModNetwork.CHANNEL.sendToServer(new ToggleSmartDoublingC2SPacket()); } ) { @@ -125,7 +122,6 @@ public abstract class PatternProviderScreenMixin if (this.menu instanceof PatternProviderMenuAdvancedSync sync) { desired = sync.eap$getAdvancedBlockingSynced(); } - LOGGER.debug("[EAP] updateBeforeRender tick (adv): desired={}", desired); this.eap$AdvancedBlockingEnabled = desired; this.eap$AdvancedBlockingToggle.set(desired ? YesNo.YES : YesNo.NO); } @@ -135,7 +131,6 @@ public abstract class PatternProviderScreenMixin if (this.menu instanceof PatternProviderMenuDoublingSync sync2) { desired2 = sync2.eap$getSmartDoublingSynced(); } - LOGGER.debug("[EAP] updateBeforeRender tick (dbl): desired={}", desired2); this.eap$SmartDoublingEnabled = desired2; this.eap$SmartDoublingToggle.set(desired2 ? YesNo.YES : YesNo.NO); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicAdvancedMixin.java index 5cff7ca..18e5a4e 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicAdvancedMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicAdvancedMixin.java @@ -22,7 +22,7 @@ import java.util.Collections; @Mixin(value = PatternProviderLogic.class, remap = false) public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder { @Unique - private static final String EPP_ADV_BLOCKING_KEY = "epp_advanced_blocking"; + private static final String EAP_ADV_BLOCKING_KEY = "eap_advanced_blocking"; @Unique private boolean eap$advancedBlocking = false; @@ -39,13 +39,13 @@ public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder @Inject(method = "writeToNBT", at = @At("TAIL")) private void eap$writeAdvancedToNbt(CompoundTag tag, CallbackInfo ci) { - tag.putBoolean(EPP_ADV_BLOCKING_KEY, this.eap$advancedBlocking); + tag.putBoolean(EAP_ADV_BLOCKING_KEY, this.eap$advancedBlocking); } @Inject(method = "readFromNBT", at = @At("TAIL")) private void eap$readAdvancedFromNbt(CompoundTag tag, CallbackInfo ci) { - if (tag.contains(EPP_ADV_BLOCKING_KEY)) { - this.eap$advancedBlocking = tag.getBoolean(EPP_ADV_BLOCKING_KEY); + if (tag.contains(EAP_ADV_BLOCKING_KEY)) { + this.eap$advancedBlocking = tag.getBoolean(EAP_ADV_BLOCKING_KEY); } } @@ -95,13 +95,13 @@ public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder @Inject(method = "exportSettings(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("TAIL")) private void onExportSettings(CompoundTag output, CallbackInfo ci) { System.out.println(this.eap$advancedBlocking); - output.putBoolean("eap_advanced_blocking", this.eap$advancedBlocking); + output.putBoolean(EAP_ADV_BLOCKING_KEY, this.eap$advancedBlocking); } @Inject(method = "importSettings(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/entity/player/Player;)V", at = @At("TAIL")) private void onImportSettings(CompoundTag input, Player player, CallbackInfo ci) { - if (input.contains("eap_advanced_blocking")) { - this.eap$advancedBlocking = input.getBoolean("eap_advanced_blocking"); + if (input.contains(EAP_ADV_BLOCKING_KEY)) { + this.eap$advancedBlocking = input.getBoolean(EAP_ADV_BLOCKING_KEY); // 持久化到 world this.saveChanges(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java index 462506f..ff3152d 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/helpers/PatternProviderLogicDoublingMixin.java @@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(value = PatternProviderLogic.class, remap = false) public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder { @Unique - private static final String EPP_SMART_DOUBLING_KEY = "epp_smart_doubling"; + private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling"; @Unique private boolean eap$smartDoubling = false; @@ -47,13 +47,13 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder { @Inject(method = "writeToNBT", at = @At("TAIL")) private void eap$writeSmartDoublingToNbt(CompoundTag tag, CallbackInfo ci) { - tag.putBoolean(EPP_SMART_DOUBLING_KEY, this.eap$smartDoubling); + tag.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); } @Inject(method = "readFromNBT", at = @At("TAIL")) private void eap$readSmartDoublingFromNbt(CompoundTag tag, CallbackInfo ci) { - if (tag.contains(EPP_SMART_DOUBLING_KEY)) { - this.eap$smartDoubling = tag.getBoolean(EPP_SMART_DOUBLING_KEY); + if (tag.contains(EAP_SMART_DOUBLING_KEY)) { + this.eap$smartDoubling = tag.getBoolean(EAP_SMART_DOUBLING_KEY); } } @@ -77,13 +77,13 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder { @Inject(method = "exportSettings(Lnet/minecraft/nbt/CompoundTag;)V", at = @At("TAIL")) private void onExportSettings(CompoundTag output, CallbackInfo ci) { System.out.println(this.eap$smartDoubling); - output.putBoolean("eap_smart_doubling", this.eap$smartDoubling); + output.putBoolean(EAP_SMART_DOUBLING_KEY, this.eap$smartDoubling); } @Inject(method = "importSettings(Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/entity/player/Player;)V", at = @At("TAIL")) private void onImportSettings(CompoundTag input, Player player, CallbackInfo ci) { - if (input.contains("eap_smart_doubling")) { - this.eap$smartDoubling = input.getBoolean("eap_smart_doubling"); + if (input.contains(EAP_SMART_DOUBLING_KEY)) { + this.eap$smartDoubling = input.getBoolean(EAP_SMART_DOUBLING_KEY); // 持久化到 world this.saveChanges(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java index 5e8fade..8a1fb05 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java @@ -15,7 +15,6 @@ import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; @@ -36,7 +35,6 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide var l = this.logic; if (l instanceof AdvancedBlockingHolder holder) { this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); - LOGGER.debug("[EAP] Menu broadcastChanges HEAD: eap$AdvancedBlocking={}", this.eap$AdvancedBlocking); } } } @@ -49,9 +47,7 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide if (l instanceof AdvancedBlockingHolder holder) { this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking(); } - } catch (Throwable t) { - LOGGER.error("Error initializing advanced sync", t); - } + } catch (Throwable ignored) {} } // 构造器尾注入(protected ctor with MenuType) @@ -71,13 +67,4 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide public boolean eap$getAdvancedBlockingSynced() { return this.eap$AdvancedBlocking; } - - // 调试:当 Screen 每帧读取这些 getter 时打印,验证 Mixin 是否生效 - @Inject(method = "getBlockingMode", at = @At("HEAD"), remap = false) - private void eap$debug_getBlockingMode(CallbackInfoReturnable cir) { - } - - @Inject(method = "getShowInAccessTerminal", at = @At("HEAD"), remap = false) - private void eap$debug_getShowInAccessTerminal(CallbackInfoReturnable cir) { - } } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java index 0e184f4..822c22f 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java @@ -33,7 +33,6 @@ public abstract class PatternProviderMenuDoublingMixin implements PatternProvide var l = this.logic; if (l instanceof SmartDoublingHolder holder) { this.eap$SmartDoubling = holder.eap$getSmartDoubling(); - LOGGER.debug("[EAP] Menu broadcastChanges HEAD: eap$SmartDoubling={}", this.eap$SmartDoubling); } } } diff --git a/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java b/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java index f58f500..2711206 100644 --- a/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/ToggleAdvancedBlockingC2SPacket.java @@ -4,10 +4,12 @@ import appeng.api.config.Settings; import appeng.api.config.YesNo; import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.AdvancedBlockingHolder; +import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkEvent; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; import java.util.function.Supplier; @@ -29,19 +31,32 @@ public class ToggleAdvancedBlockingC2SPacket { ctx.enqueueWork(() -> { ServerPlayer player = ctx.getSender(); if (player == null) return; - if (!(player.containerMenu instanceof PatternProviderMenu menu)) return; - // 通过 accessor 获取逻辑与当前状态 - var accessor = (PatternProviderMenuAdvancedAccessor) menu; - var logic = accessor.eap$logic(); - if (logic instanceof AdvancedBlockingHolder holder) { - boolean current = holder.eap$getAdvancedBlocking(); - boolean next = !current; - holder.eap$setAdvancedBlocking(next); - // 自动开启原版阻挡 - logic.getConfigManager().putSetting(Settings.BLOCKING_MODE, YesNo.YES); - // 保存并触发 AE2 的菜单 @GuiSync 广播到所有观看该菜单的玩家 - logic.saveChanges(); + var containerMenu = player.containerMenu; + if (containerMenu instanceof PatternProviderMenu menu) { + var accessor = (PatternProviderMenuAdvancedAccessor) menu; + var logic = accessor.eap$logic(); + if (logic instanceof AdvancedBlockingHolder holder) { + boolean current = holder.eap$getAdvancedBlocking(); + boolean next = !current; + holder.eap$setAdvancedBlocking(next); + // 自动开启原版阻挡 + logic.getConfigManager().putSetting(Settings.BLOCKING_MODE, YesNo.YES); + // 保存并触发 AE2 的菜单 @GuiSync 广播到所有观看该菜单的玩家 + logic.saveChanges(); + } + }else if (containerMenu instanceof AdvPatternProviderMenu menu){ + var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu; + var logic = accessor.eap$logic(); + if (logic instanceof AdvancedBlockingHolder holder) { + boolean current = holder.eap$getAdvancedBlocking(); + boolean next = !current; + holder.eap$setAdvancedBlocking(next); + // 自动开启原版阻挡 + logic.getConfigManager().putSetting(Settings.BLOCKING_MODE, YesNo.YES); + // 保存并触发 AE2 的菜单 @GuiSync 广播到所有观看该菜单的玩家 + logic.saveChanges(); + } } }); ctx.setPacketHandled(true); diff --git a/src/main/java/com/extendedae_plus/network/ToggleSmartDoublingC2SPacket.java b/src/main/java/com/extendedae_plus/network/ToggleSmartDoublingC2SPacket.java index 3ad6405..88d832a 100644 --- a/src/main/java/com/extendedae_plus/network/ToggleSmartDoublingC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/ToggleSmartDoublingC2SPacket.java @@ -2,10 +2,12 @@ package com.extendedae_plus.network; import appeng.menu.implementations.PatternProviderMenu; import com.extendedae_plus.api.SmartDoublingHolder; +import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor; import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerPlayer; import net.minecraftforge.network.NetworkEvent; +import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; import java.util.function.Supplier; @@ -27,15 +29,25 @@ public class ToggleSmartDoublingC2SPacket { ctx.enqueueWork(() -> { ServerPlayer player = ctx.getSender(); if (player == null) return; - if (!(player.containerMenu instanceof PatternProviderMenu menu)) return; - - var accessor = (PatternProviderMenuAdvancedAccessor) menu; - var logic = accessor.eap$logic(); - if (logic instanceof SmartDoublingHolder holder) { - boolean current = holder.eap$getSmartDoubling(); - boolean next = !current; - holder.eap$setSmartDoubling(next); - logic.saveChanges(); + var containerMenu = player.containerMenu; + if (containerMenu instanceof PatternProviderMenu menu) { + var accessor = (PatternProviderMenuAdvancedAccessor) menu; + var logic = accessor.eap$logic(); + if (logic instanceof SmartDoublingHolder holder) { + boolean current = holder.eap$getSmartDoubling(); + boolean next = !current; + holder.eap$setSmartDoubling(next); + logic.saveChanges(); + } + }else if (containerMenu instanceof AdvPatternProviderMenu menu){ + var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu; + var logic = accessor.eap$logic(); + if (logic instanceof SmartDoublingHolder holder) { + boolean current = holder.eap$getSmartDoubling(); + boolean next = !current; + holder.eap$setSmartDoubling(next); + logic.saveChanges(); + } } }); ctx.setPacketHandled(true); diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index af79b32..edc5469 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -7,6 +7,8 @@ "PickFromWirelessMixin", "accessor.AbstractContainerScreenAccessor", "accessor.ScreenAccessor", + "advancedae.client.gui.AdvPatternProviderScreenMixin", + "advancedae.client.gui.SmallAdvPatternProviderScreenMixin", "ae2.QuartzCuttingKnifeItemMixin", "ae2.accessor.AEBaseScreenAccessor", "ae2.accessor.AEBaseScreenInvoker", @@ -29,6 +31,13 @@ "jei.accessor.BookmarkOverlayAccessor" ], "mixins": [ + "advancedae.AdvPatternProviderLogicContainsRedirectMixin", + "advancedae.accessor.AdvPatternProviderLogicPatternsAccessor", + "advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor", + "advancedae.helpers.AdvPatternProviderLogicAdvancedMixin", + "advancedae.helpers.AdvPatternProviderLogicDoublingMixin", + "advancedae.menu.AdvPatternProviderMenuAdvancedMixin", + "advancedae.menu.AdvPatternProviderMenuDoublingMixin", "ae2.AEProcessingPatternMixin", "ae2.CraftingCalculationMixin", "ae2.CraftingCPUClusterMixin", From 77c5246232ba1439ac7f277f0b4876400e3eff3f Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Mon, 15 Sep 2025 18:25:59 +0800 Subject: [PATCH 29/44] =?UTF-8?q?fix:=20PatternProviderCloseMixin=E6=B7=B7?= =?UTF-8?q?=E5=85=A5=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mixin/ae2/client/gui/PatternProviderCloseMixin.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderCloseMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderCloseMixin.java index 767e888..4613b2c 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderCloseMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/PatternProviderCloseMixin.java @@ -3,19 +3,13 @@ package com.extendedae_plus.mixin.ae2.client.gui; import appeng.client.gui.implementations.PatternProviderScreen; import com.extendedae_plus.content.ClientPatternHighlightStore; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; -import net.minecraft.world.inventory.AbstractContainerMenu; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(value = AbstractContainerScreen.class, remap = false) +@Mixin(value = AbstractContainerScreen.class) public class PatternProviderCloseMixin { - - @Shadow - protected AbstractContainerMenu menu; - @Inject(method = "removed", at = @At("HEAD")) private void onRemoved(CallbackInfo ci) { try { From 224fa2a37b348ef0a139b003b63600985c5602d0 Mon Sep 17 00:00:00 2001 From: GaLicn <133291877+GaLicn@users.noreply.github.com> Date: Mon, 15 Sep 2025 21:01:34 +0800 Subject: [PATCH 30/44] =?UTF-8?q?ME=E6=8E=A5=E5=8F=A3=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=80=8D=E5=A2=9E=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae2/client/gui/InterfaceScreenMixin.java | 179 ++++++++++++++++++ .../resources/extendedae_plus.mixins.json | 1 + 2 files changed, 180 insertions(+) create mode 100644 src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java new file mode 100644 index 0000000..d78edc0 --- /dev/null +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java @@ -0,0 +1,179 @@ +package com.extendedae_plus.mixin.ae2.client.gui; + +import appeng.client.gui.AEBaseScreen; +import appeng.client.gui.implementations.InterfaceScreen; +import appeng.menu.AEBaseMenu; +import com.extendedae_plus.NewIcon; +import com.extendedae_plus.mixin.accessor.AbstractContainerScreenAccessor; +import com.extendedae_plus.mixin.accessor.ScreenAccessor; +import com.glodblock.github.extendedae.client.button.ActionEPPButton; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.network.chat.Component; +import com.mojang.logging.LogUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** + * 在 AE2 的 ME 接口界面注入倍增/除法按钮(x2/÷2、x5/÷5、x10/÷10)。 + * 点击逻辑暂时留空,仅完成按钮创建、注册与布局维护。 + */ +@Mixin(AEBaseScreen.class) +public abstract class InterfaceScreenMixin { + + @Unique private ActionEPPButton eap$x2Button; + @Unique private ActionEPPButton eap$divideBy2Button; + @Unique private ActionEPPButton eap$x5Button; + @Unique private ActionEPPButton eap$divideBy5Button; + @Unique private ActionEPPButton eap$x10Button; + @Unique private ActionEPPButton eap$divideBy10Button; + + @Unique private int eap$lastLeftPos = -1; + @Unique private int eap$lastTopPos = -1; + @Unique private int eap$lastImageWidth = -1; + @Unique private int eap$lastImageHeight = -1; + + @Inject(method = "init", at = @At("TAIL")) + private void eap$addScaleButtons(CallbackInfo ci) { + // 仅在 InterfaceScreen 实例中添加 + if (!(((Object) this) instanceof InterfaceScreen)) { + return; + } + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] init tail reached, preparing scale buttons."); } catch (Throwable ignored) {} + // 避免重复创建 + if (eap$x2Button == null) { + eap$x2Button = new ActionEPPButton((b) -> { + // 点击逻辑留空 + }, NewIcon.MULTIPLY2); + eap$x2Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply2"))); + eap$x2Button.setVisibility(true); + } + if (eap$divideBy2Button == null) { + eap$divideBy2Button = new ActionEPPButton((b) -> { + // 点击逻辑留空 + }, NewIcon.DIVIDE2); + eap$divideBy2Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide2"))); + eap$divideBy2Button.setVisibility(true); + } + if (eap$x5Button == null) { + eap$x5Button = new ActionEPPButton((b) -> { + // 点击逻辑留空 + }, NewIcon.MULTIPLY5); + eap$x5Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply5"))); + eap$x5Button.setVisibility(true); + } + if (eap$divideBy5Button == null) { + eap$divideBy5Button = new ActionEPPButton((b) -> { + // 点击逻辑留空 + }, NewIcon.DIVIDE5); + eap$divideBy5Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide5"))); + eap$divideBy5Button.setVisibility(true); + } + if (eap$x10Button == null) { + eap$x10Button = new ActionEPPButton((b) -> { + // 点击逻辑留空 + }, NewIcon.MULTIPLY10); + eap$x10Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply10"))); + eap$x10Button.setVisibility(true); + } + if (eap$divideBy10Button == null) { + eap$divideBy10Button = new ActionEPPButton((b) -> { + // 点击逻辑留空 + }, NewIcon.DIVIDE10); + eap$divideBy10Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide10"))); + eap$divideBy10Button.setVisibility(true); + } + + // 注册到渲染与交互列表 + var accessor = (ScreenAccessor) (Object) this; + if (!accessor.eap$getRenderables().contains(eap$divideBy2Button)) accessor.eap$getRenderables().add(eap$divideBy2Button); + if (!accessor.eap$getChildren().contains(eap$divideBy2Button)) accessor.eap$getChildren().add(eap$divideBy2Button); + if (!accessor.eap$getRenderables().contains(eap$x2Button)) accessor.eap$getRenderables().add(eap$x2Button); + if (!accessor.eap$getChildren().contains(eap$x2Button)) accessor.eap$getChildren().add(eap$x2Button); + if (!accessor.eap$getRenderables().contains(eap$divideBy5Button)) accessor.eap$getRenderables().add(eap$divideBy5Button); + if (!accessor.eap$getChildren().contains(eap$divideBy5Button)) accessor.eap$getChildren().add(eap$divideBy5Button); + if (!accessor.eap$getRenderables().contains(eap$x5Button)) accessor.eap$getRenderables().add(eap$x5Button); + if (!accessor.eap$getChildren().contains(eap$x5Button)) accessor.eap$getChildren().add(eap$x5Button); + if (!accessor.eap$getRenderables().contains(eap$divideBy10Button)) accessor.eap$getRenderables().add(eap$divideBy10Button); + if (!accessor.eap$getChildren().contains(eap$divideBy10Button)) accessor.eap$getChildren().add(eap$divideBy10Button); + if (!accessor.eap$getRenderables().contains(eap$x10Button)) accessor.eap$getRenderables().add(eap$x10Button); + if (!accessor.eap$getChildren().contains(eap$x10Button)) accessor.eap$getChildren().add(eap$x10Button); + + // 初次定位 + eap$relayoutButtons(); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] buttons added and laid out."); } catch (Throwable ignored) {} + } + + @Inject(method = "containerTick", at = @At("TAIL")) + private void eap$ensureButtons(CallbackInfo ci) { + if (!(((Object) this) instanceof InterfaceScreen)) { + return; + } + var accessor = (ScreenAccessor) (Object) this; + // 若被其他模组清空,补回 + if (eap$divideBy2Button != null && !accessor.eap$getRenderables().contains(eap$divideBy2Button)) { + accessor.eap$getRenderables().add(eap$divideBy2Button); + accessor.eap$getChildren().add(eap$divideBy2Button); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] re-added divide2 button to renderables."); } catch (Throwable ignored) {} + } + if (eap$x2Button != null && !accessor.eap$getRenderables().contains(eap$x2Button)) { + accessor.eap$getRenderables().add(eap$x2Button); + accessor.eap$getChildren().add(eap$x2Button); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] re-added x2 button to renderables."); } catch (Throwable ignored) {} + } + if (eap$divideBy5Button != null && !accessor.eap$getRenderables().contains(eap$divideBy5Button)) { + accessor.eap$getRenderables().add(eap$divideBy5Button); + accessor.eap$getChildren().add(eap$divideBy5Button); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] re-added divide5 button to renderables."); } catch (Throwable ignored) {} + } + if (eap$x5Button != null && !accessor.eap$getRenderables().contains(eap$x5Button)) { + accessor.eap$getRenderables().add(eap$x5Button); + accessor.eap$getChildren().add(eap$x5Button); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] re-added x5 button to renderables."); } catch (Throwable ignored) {} + } + if (eap$divideBy10Button != null && !accessor.eap$getRenderables().contains(eap$divideBy10Button)) { + accessor.eap$getRenderables().add(eap$divideBy10Button); + accessor.eap$getChildren().add(eap$divideBy10Button); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] re-added divide10 button to renderables."); } catch (Throwable ignored) {} + } + if (eap$x10Button != null && !accessor.eap$getRenderables().contains(eap$x10Button)) { + accessor.eap$getRenderables().add(eap$x10Button); + accessor.eap$getChildren().add(eap$x10Button); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] re-added x10 button to renderables."); } catch (Throwable ignored) {} + } + // 尺寸变化时重新定位 + int curLeft = ((AbstractContainerScreenAccessor) (Object) this).eap$getLeftPos(); + int curTop = ((AbstractContainerScreenAccessor) (Object) this).eap$getTopPos(); + int curImgW = ((AbstractContainerScreenAccessor) (Object) this).eap$getImageWidth(); + int curImgH = ((AbstractContainerScreenAccessor) (Object) this).eap$getImageHeight(); + if (curLeft != eap$lastLeftPos || curTop != eap$lastTopPos || curImgW != eap$lastImageWidth || curImgH != eap$lastImageHeight) { + eap$lastLeftPos = curLeft; + eap$lastTopPos = curTop; + eap$lastImageWidth = curImgW; + eap$lastImageHeight = curImgH; + eap$relayoutButtons(); + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] relayout due to bounds change: left={}, top={}, w={}, h={}", curLeft, curTop, curImgW, curImgH); } catch (Throwable ignored) {} + } + } + + @Unique + private void eap$relayoutButtons() { + try { + int leftPos = ((AbstractContainerScreenAccessor) (Object) this).eap$getLeftPos(); + int topPos = ((AbstractContainerScreenAccessor) (Object) this).eap$getTopPos(); + int imageWidth = ((AbstractContainerScreenAccessor) (Object) this).eap$getImageWidth(); + // 按照样板供应器界面一致的布局:界面右缘外侧竖排 + int bx = leftPos + imageWidth + 1; + int by = topPos + 20; + int spacing = 22; + if (eap$divideBy2Button != null) { eap$divideBy2Button.setX(bx); eap$divideBy2Button.setY(by); } + if (eap$x2Button != null) { eap$x2Button.setX(bx); eap$x2Button.setY(by + spacing); } + if (eap$divideBy5Button != null) { eap$divideBy5Button.setX(bx); eap$divideBy5Button.setY(by + spacing * 2); } + if (eap$x5Button != null) { eap$x5Button.setX(bx); eap$x5Button.setY(by + spacing * 3); } + if (eap$divideBy10Button != null) { eap$divideBy10Button.setX(bx); eap$divideBy10Button.setY(by + spacing * 4); } + if (eap$x10Button != null) { eap$x10Button.setX(bx); eap$x10Button.setY(by + spacing * 5); } + } catch (Throwable ignored) {} + } +} diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index af79b32..a6d9664 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -15,6 +15,7 @@ "ae2.accessor.PatternAccessTermScreenSlotsRowAccessor", "ae2.client.gui.AEBaseScreenMixin", "ae2.client.gui.PatternEncodingTermScreenMixin", + "ae2.client.gui.InterfaceScreenMixin", "ae2.client.gui.PatternProviderCloseMixin", "ae2.client.gui.PatternProviderScreenMixin", "ae2.client.gui.SlotGridLayoutMixin", From 9bdda0526f532d1ff7f2611ccd397b6c51315885 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Tue, 16 Sep 2025 17:53:17 +0800 Subject: [PATCH 31/44] =?UTF-8?q?feat:=20=E6=97=A0=E9=99=90=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E7=A3=81=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + .../com/extendedae_plus/ExtendedAEPlus.java | 15 + .../InfinityBigIntegerCellHandler.java | 36 ++ .../InfinityBigIntegerCellInventory.java | 375 ++++++++++++++++++ .../ae/items/InfinityBigIntegerCellItem.java | 68 ++++ .../extendedae_plus/init/ModCreativeTabs.java | 2 + .../com/extendedae_plus/init/ModItems.java | 6 + .../util/storage/InfinityDataStorage.java | 61 +++ .../util/storage/InfinityStorageManager.java | 114 ++++++ 9 files changed, 678 insertions(+) create mode 100644 src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java create mode 100644 src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java create mode 100644 src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java create mode 100644 src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java create mode 100644 src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java diff --git a/README.md b/README.md index d8d6011..ca05466 100644 --- a/README.md +++ b/README.md @@ -42,5 +42,6 @@ ExtendedAE Plus 是一个面向 Applied Energistics 2 与 ExtendedAE 的功能 - Applied Energistics 2(AE2):MIT License - SpongePowered Mixin:MIT License - Configuration(by Toma):MIT License +- AE2Things(by ProjectET):MIT License 请查阅各上游项目以获取完整与最新的许可证信息。第三方组件的许可证与版权归其各自作者所有。 diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 5bc94d1..6a84267 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -1,14 +1,19 @@ package com.extendedae_plus; +import appeng.api.storage.StorageCells; import appeng.menu.locator.MenuLocators; +import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler; import com.extendedae_plus.client.ClientRegistrar; import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.init.*; import com.extendedae_plus.menu.locator.CuriosItemLocator; +import com.extendedae_plus.util.storage.InfinityStorageManager; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerLevel; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.client.event.ModelEvent; import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.level.LevelEvent; import net.minecraftforge.eventbus.api.IEventBus; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; @@ -46,6 +51,7 @@ public class ExtendedAEPlus { // 注册到Forge事件总线 MinecraftForge.EVENT_BUS.register(this); + MinecraftForge.EVENT_BUS.addListener(ExtendedAEPlus::onLevelLoad); // 注册通用配置 ModConfig.init(); // ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); @@ -55,6 +61,8 @@ public class ExtendedAEPlus { * 通用初始化设置 */ private void commonSetup(final FMLCommonSetupEvent event) { + StorageCells.addCellHandler(InfinityBigIntegerCellHandler.INSTANCE); + // 注册本模组网络通道与数据包 event.enqueueWork(() -> { // 注册升级卡 @@ -104,4 +112,11 @@ public class ExtendedAEPlus { } catch (Exception ignored) {} } } + + // 在世界加载时注册/加载 SavedData + private static void onLevelLoad(LevelEvent.Load event) { + if (event.getLevel() instanceof ServerLevel serverLevel) { + InfinityStorageManager.getForLevel(serverLevel); + } + } } diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java new file mode 100644 index 0000000..bc7c29c --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java @@ -0,0 +1,36 @@ +package com.extendedae_plus.ae.api.storage; + +import appeng.api.storage.cells.ICellHandler; +import appeng.api.storage.cells.ISaveProvider; +import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; +import net.minecraft.world.item.ItemStack; + +/** + * InfinityBigIntegerCellHandler + * + * 该类实现 AE2 的 ICellHandler,用于: + * - 判定某个 ItemStack 是否为本 mod 的 Infinity 存储单元 + * - 在 AE2 请求访问或创建存储单元时,创建并返回对应的 StorageCell 实例 + */ +public class InfinityBigIntegerCellHandler implements ICellHandler { + + /** Handler 单例,供注册与调用使用 */ + public static final InfinityBigIntegerCellHandler INSTANCE = new InfinityBigIntegerCellHandler(); + + /** + * 判断给定的 ItemStack 是否为 InfinityBigIntegerCell + */ + @Override + public boolean isCell(ItemStack is) { + return is.getItem() instanceof InfinityBigIntegerCellItem; + } + + /** + * 在 AE2 需要访问或创建存储单元时返回对应的 InfinityBigIntegerCellInventory(StorageCell 实现)。 + * 参数 container 为 AE2 提供的保存回调(ISaveProvider),当 cell 需要持久化时会调用它。 + */ + @Override + public InfinityBigIntegerCellInventory getCellInventory(ItemStack is, ISaveProvider container) { + return InfinityBigIntegerCellInventory.createInventory(is, container); + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java new file mode 100644 index 0000000..19273c4 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -0,0 +1,375 @@ +package com.extendedae_plus.ae.api.storage; + +import appeng.api.config.Actionable; +import appeng.api.networking.security.IActionSource; +import appeng.api.stacks.AEItemKey; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.KeyCounter; +import appeng.api.storage.cells.CellState; +import appeng.api.storage.cells.ISaveProvider; +import appeng.api.storage.cells.StorageCell; +import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; +import com.extendedae_plus.util.storage.InfinityDataStorage; +import com.extendedae_plus.util.storage.InfinityStorageManager; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.event.TickEvent; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.util.UUID; +import java.util.concurrent.ConcurrentLinkedQueue; + +/** + * InfinityBigIntegerCellInventory + *

+ * 本类实现 AE2 的 StorageCell,表示单个 Infinity 存储单元的运行时数据与行为。 + * 主要职责: + * - 在内存中维护条目映射 (AEKey -> BigInteger 数量) + * - 提供插入/提取/列举/持久化等操作的实现 + * - 通过 UUID 将 ItemStack 与世界级的 SavedData 关联以实现持久化 + *

+ * 重要字段: + * - stack: 关联的 ItemStack,NB T 中保存 UUID 与缓存信息 + * - container: AE2 提供的保存回调 (ISaveProvider),用于合并与触发持久化 + * - storedMap: 延迟初始化的内存映射,减少未使用时内存占用 + * - totalStored: 缓存的总数量 (BigInteger),避免频繁全表扫描 + * - isPersisted: 标记内存状态是否已同步到持久层 + */ +public class InfinityBigIntegerCellInventory implements StorageCell { + + // 待持久化队列(用于 debounce:在服务器 tick 中合并持久化) + private static final ConcurrentLinkedQueue PENDING_PERSIST = new ConcurrentLinkedQueue<>(); + // 数字格式化对象,保留两位小数(复用以减少对象分配) + private static final DecimalFormat DF = new DecimalFormat("#.##"); + + static { + // 在类加载时注册服务器 tick 监听器,用于在主线程合并写入 + try { + MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerTick); + } catch (Throwable ignored) { + // 保守降级:若注册失败,不阻塞实例化 + } + } + + // 关联的 ItemStack(含可能的 uuid NBT) + private final ItemStack stack; + // AE2 提供的保存提供者,用于在容器中批量保存时触发回调 + private final ISaveProvider container; + // 内存中的键-数量映射(使用 BigInteger 支持超长数量,延迟初始化) + private Object2ObjectMap storedMap = null; + // 标记是否已持久化到 SavedData + private boolean isPersisted = true; + // 缓存的总存储量,避免每次调用进行全表扫描 + private BigInteger totalStored = BigInteger.ZERO; + + /** + * 私有构造器:通过 createInventory 工厂方法调用 + * + * @param stack 关联的物品堆 + * @param saveProvider AE2 的保存回调(可为 null) + */ + private InfinityBigIntegerCellInventory(ItemStack stack, ISaveProvider saveProvider) { + this.stack = stack; + container = saveProvider; + // 不在构造时创建 storedMap,推迟到实际访问或首次写入时初始化 + this.storedMap = null; + } + + // 创建存储单元库存实例的静态方法 + static InfinityBigIntegerCellInventory createInventory(ItemStack stack, ISaveProvider saveProvider) { + if (stack.getItem() instanceof InfinityBigIntegerCellItem) { + return new InfinityBigIntegerCellInventory(stack, saveProvider); + } + return null; + } + + // 获取全局存储实例 + private static InfinityStorageManager getStorageInstance() { + return InfinityStorageManager.INSTANCE; + } + + // 服务器 tick 回调:合并并执行待持久化项 + private static void onServerTick(TickEvent.ServerTickEvent event) { + if (event.phase != TickEvent.Phase.END) return; + InfinityBigIntegerCellInventory inv; + // 处理本次 tick 中的全部待持久化项 + while ((inv = PENDING_PERSIST.poll()) != null) { + try { + if (!inv.isPersisted) { + inv.persist(); + } + } catch (Throwable ignored) { + // 忽略单项错误,继续处理其余队列 + } + } + } + + // 将 BigInteger 格式化为带单位的字符串,保留两位小数 + public static String formatBigInteger(BigInteger number) { + // 使用局部 DF(非线程安全),但 Minecraft 通常在主线程运行 + BigDecimal bd = new BigDecimal(number); + BigDecimal thousand = new BigDecimal(1000); + String[] units = new String[]{"", "K", "M", "G", "T", "P", "E", "Z", "Y"}; + int idx = 0; + while (bd.compareTo(thousand) >= 0 && idx < units.length - 1) { + bd = bd.divide(thousand, 2, RoundingMode.HALF_UP); + idx++; + } + if (idx == 0) { + return bd.setScale(0, RoundingMode.DOWN).toPlainString(); + } + return DF.format(bd.doubleValue()) + units[idx]; + } + + // 获取当前存储单元的数据存储对象 + private InfinityDataStorage getCellStorage() { + if (this.getUUID() == null) { + // 如果没有UUID,返回空存储 + return InfinityDataStorage.EMPTY; + } else { + // 否则获取或创建对应UUID的存储 + return getStorageInstance().getOrCreateCell(getUUID()); + } + } + + // 获取存储单元状态(空/非空) + @Override + public CellState getStatus() { + if (this.getCellStoredMap().isEmpty()) { + return CellState.EMPTY; + } + return CellState.NOT_EMPTY; + } + + // 获取存储单元的待机能耗 + @Override + public double getIdleDrain() { + return 512; + } + + // 获取存储单元的描述(此处返回null,可自定义) + @Override + public Component getDescription() { + return null; + } + + // 判断物品堆栈是否有UUID + public boolean hasUUID() { + return stack.hasTag() && stack.getOrCreateTag().contains("uuid"); + } + + // 获取物品堆栈的UUID + public UUID getUUID() { + if (this.hasUUID()) + return stack.getOrCreateTag().getUUID("uuid"); + else + return null; + } + + // 获取或初始化存储映射 + private Object2ObjectMap getCellStoredMap() { + if (storedMap == null) { + storedMap = new Object2ObjectOpenHashMap<>(); + this.loadCellStoredMap(); + } + return storedMap; + } + + // 从存储中加载物品映射 + private void loadCellStoredMap() { + boolean corruptedTag = false; // 标记数据是否损坏 + if (!stack.hasTag()) return; + ListTag keys = this.getCellStorage().keys; + ListTag amounts = this.getCellStorage().amounts; + int len = Math.min(keys.size(), amounts.size()); + for (int i = 0; i < len; i++) { + AEKey key = AEKey.fromTagGeneric(keys.getCompound(i)); + CompoundTag amtTag = amounts.getCompound(i); + try { + BigInteger amount; + if (amtTag.contains("l")) { + long v = amtTag.getLong("l"); + amount = BigInteger.valueOf(v); + } else if (amtTag.contains("s")) { + amount = new BigInteger(amtTag.getString("s")); + } else { + corruptedTag = true; + continue; + } + if (amount.compareTo(BigInteger.ZERO) <= 0 || key == null) { + corruptedTag = true; + } else { + // storedMap 已在 getCellStoredMap() 中初始化,直接使用字段以避免额外方法开销 + storedMap.put(key, amount); + // 更新缓存的总数 + totalStored = totalStored.add(amount); + } + } catch (NumberFormatException ex) { + corruptedTag = true; + } + } + // 如果有损坏,保存修正后的数据 + if (corruptedTag) { + this.saveChanges(); + } + } + + // 标记数据需要保存,并通知容器或直接持久化 + private void saveChanges() { + // 标记为未持久化,交由容器或延迟任务合并写入以减少 I/O + isPersisted = false; + if (container != null) { + // 当存在容器时,优先让容器统一处理持久化 + container.saveChanges(); + } else { + // 如果没有容器,入队等待服务器 tick 在主线程统一持久化,避免频繁 I/O + if (!PENDING_PERSIST.contains(this)) { + PENDING_PERSIST.offer(this); + } + } + } + + // 获取所有可用的物品堆栈及其数量 + @Override + public void getAvailableStacks(KeyCounter out) { + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); + Object2ObjectMap map = getCellStoredMap(); + for (Object2ObjectMap.Entry entry : map.object2ObjectEntrySet()) { + BigInteger v = entry.getValue(); + long toAdd = v.compareTo(maxLong) > 0 ? Long.MAX_VALUE : v.longValue(); + out.add(entry.getKey(), toAdd); + } + } + + // 持久化存储单元数据到全局存储 + @Override + public void persist() { + if (this.isPersisted) + return; + Object2ObjectMap map = this.getCellStoredMap(); + if (map.isEmpty()) { + // 如果存储为空,移除UUID和全局存储中的数据 + if (this.hasUUID()) { + getStorageInstance().removeCell(getUUID()); + if (stack.getTag() != null) { + stack.getTag().remove("uuid"); + // 移除缓存的 total 字段 + stack.getTag().remove("total"); + } + } + return; + } + // 构建要保存的Key和数量列表(混合表示:long 或 string) + ListTag amountTags = new ListTag(); + ListTag keys = new ListTag(); + for (Object2ObjectMap.Entry entry : map.object2ObjectEntrySet()) { + BigInteger amount = entry.getValue(); + if (amount.compareTo(BigInteger.ZERO) > 0) { + keys.add(entry.getKey().toTagGeneric()); + CompoundTag amt = new CompoundTag(); + if (amount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) { + amt.putLong("l", amount.longValue()); + } else { + amt.putString("s", amount.toString()); + } + amountTags.add(amt); + } + } + // 如果没有Key,更新为空存储,否则保存数据 + if (keys.isEmpty()) { + getStorageInstance().updateCell(this.getUUID(), new InfinityDataStorage()); + } else { + // amounts 现在为 CompoundTag 列表 + getStorageInstance().modifyCell(this.getUUID(), keys, amountTags); + } + // 将缓存的 totalStored 同步到 ItemStack 的 NBT,优先使用 long + if (stack.getOrCreateTag() != null) { + if (totalStored.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) <= 0) { + stack.getOrCreateTag().putLong("total", totalStored.longValue()); + } else { + stack.getOrCreateTag().putString("total", totalStored.toString()); + } + } + isPersisted = true; + } + + // 插入物品到存储单元 + @Override + public long insert(AEKey what, long amount, Actionable mode, IActionSource source) { + // 数量为0或类型不匹配直接返回 + if (amount == 0) + return 0; + // 不允许存储无限单元自身 + if (what instanceof AEItemKey itemKey && itemKey.getItem() instanceof InfinityBigIntegerCellItem) + return 0; + // 如果没有UUID,生成UUID并初始化存储 + if (!this.hasUUID()) { + stack.getOrCreateTag().putUUID("uuid", UUID.randomUUID()); + getStorageInstance().getOrCreateCell(getUUID()); + // 确保 storedMap 初始化并从持久层加载数据 + this.getCellStoredMap(); + } + Object2ObjectMap map = this.getCellStoredMap(); + BigInteger currentAmount = map.getOrDefault(what, BigInteger.ZERO); + if (mode == Actionable.MODULATE) { + // 实际插入,更新数量并保存 + BigInteger newAmount = currentAmount.add(BigInteger.valueOf(amount)); + map.put(what, newAmount); + // 更新 cached total + totalStored = totalStored.add(BigInteger.valueOf(amount)); + this.saveChanges(); + } + return amount; + } + + // 从存储单元提取物品 + @Override + public long extract(AEKey what, long amount, Actionable mode, IActionSource source) { + Object2ObjectMap map = this.getCellStoredMap(); + BigInteger currentAmount = map.getOrDefault(what, BigInteger.ZERO); + if (currentAmount.compareTo(BigInteger.ZERO) > 0) { + BigInteger requested = BigInteger.valueOf(amount); + if (currentAmount.compareTo(requested) <= 0) { + // 提取全部 + long ret; + if (currentAmount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0) { + ret = Long.MAX_VALUE; + } else { + ret = currentAmount.longValue(); + } + if (mode == Actionable.MODULATE) { + map.remove(what); + // 更新 cached total + // 如果 currentAmount 大于 Long.MAX_VALUE,totalStored 减去 currentAmount 会保留大整数 + totalStored = totalStored.subtract(currentAmount); + this.saveChanges(); + } + return ret; + } else { + // 提取部分 + if (mode == Actionable.MODULATE) { + map.put(what, currentAmount.subtract(requested)); + // 更新 cached total + totalStored = totalStored.subtract(requested); + this.saveChanges(); + } + return amount; + } + } + return 0; + } + + // 获取存储单元内所有物品的总数量(格式化字符串) + public String getTotalStorage() { + // 使用缓存的 totalStored,避免每次全表扫描 + return formatBigInteger(totalStored); + } +} diff --git a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java new file mode 100644 index 0000000..5b550a1 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java @@ -0,0 +1,68 @@ +package com.extendedae_plus.ae.items; + +import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory; +import com.google.common.base.Preconditions; +import net.minecraft.ChatFormatting; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.LongTag; +import net.minecraft.nbt.Tag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.level.Level; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.math.BigInteger; +import java.util.List; + +public class InfinityBigIntegerCellItem extends Item { + + public InfinityBigIntegerCellItem() { + super(new Properties().stacksTo(1).fireResistant()); + } + + /** + * 在物品悬停提示中展示额外信息。 + * 功能: + * - 若 ItemStack 的 NBT 含有 UUID,则显示该 UUID(不会触发服务器加载或持久化行为) + * - 若 NBT 同步了 total 字段,则读取并格式化显示总存储量(使用 Inventory 的 formatBigInteger) + * + * 设计说明:客户端 tooltip 不主动访问服务端 SavedData,以避免不必要的 I/O 与状态变更。 + */ + @Override + public void appendHoverText(ItemStack stack, + @Nullable Level world, + @NotNull List tooltip, + @NotNull TooltipFlag context) { + Preconditions.checkArgument(stack.getItem() == this); + // 仅在 ItemStack 自身存在 UUID 时显示 UUID,避免触发持久化或加载逻辑 + CompoundTag tag = stack.getTag(); + if (tag != null && tag.contains("uuid")) { + String uuidStr = tag.getUUID("uuid").toString(); + tooltip.add( + Component.literal("UUID: ").withStyle(ChatFormatting.GRAY).append(Component.literal(uuidStr).withStyle(ChatFormatting.YELLOW)) + ); + // 读取并显示已缓存的 total(支持 long 或 string),使用格式化函数展示友好单位 + if (tag.contains("total")) { + BigInteger total = BigInteger.ZERO; + Tag t = tag.get("total"); + try { + if (t instanceof LongTag) { + total = BigInteger.valueOf(tag.getLong("total")); + } else { + String s = tag.getString("total"); + total = new BigInteger(s); + } + } catch (Exception ignored) { + // 解析失败保持为 0 + } + String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total); + tooltip.add( + Component.literal("Byte: ").withStyle(ChatFormatting.GRAY).append(Component.literal(formatted).withStyle(ChatFormatting.AQUA)) + ); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java index 68bdba4..dc4a03c 100644 --- a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java +++ b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java @@ -33,6 +33,8 @@ public final class ModCreativeTabs { output.accept(ModItems.createEntitySpeedCardStack(4)); output.accept(ModItems.createEntitySpeedCardStack(8)); output.accept(ModItems.createEntitySpeedCardStack(16)); + + output.accept(ModItems.INFINITY_BIGINT_ITEM_CELL.get()); }) .build()); } diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index 7341c99..fc6a2e5 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -6,6 +6,7 @@ import appeng.items.parts.PartModelsHelper; import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem; +import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraftforge.registries.DeferredRegister; @@ -65,6 +66,11 @@ public final class ModItems { () -> new EntitySpeedCardItem(new Item.Properties()) ); + public static final RegistryObject INFINITY_BIGINT_ITEM_CELL = ITEMS.register( + "infinity_item_cell", InfinityBigIntegerCellItem::new + ); + + /** * 为 PartItem 注册 AE2 部件模型。 * 在客户端进行模型/几何体注册时调用。 diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java new file mode 100644 index 0000000..4ef9036 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java @@ -0,0 +1,61 @@ +package com.extendedae_plus.util.storage; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; + +/** + * InfinityDataStorage + * + * 表示单个 UUID 对应的持久化数据容器,直接映射到世界存档中的一项记录。 + * 数据结构说明: + * - keys: 存放序列化后的 AEKey(每项为 CompoundTag),用于标识不同的存储条目 + * - amounts: 与 keys 一一对应的数量列表(每项为 CompoundTag),采用混合表示: + * - 当数量能放入 long 时,CompoundTag 包含键 "l" 存放 long 值 + * - 当数量超出 long 时,CompoundTag 包含键 "s" 存放 BigInteger 的字符串形式 + * + * 该类提供将内存数据与 NBT 之间互转的辅助方法,供 `SavedData` 在世界保存/加载时调用。 + */ +public class InfinityDataStorage { + + /** 空实例(表示没有数据) */ + public static final InfinityDataStorage EMPTY = new InfinityDataStorage(); + + /** 序列化的键列表(NBT ListTag,元素为 CompoundTag) */ + public ListTag keys; + /** + * 与 keys 对应的数量列表(NBT ListTag,元素为 CompoundTag): + * - 若数量能放入 long,则 CompoundTag 包含键 "l"(long) + * - 否则包含键 "s"(String) 存放 BigInteger 的字符串形式 + */ + public ListTag amounts; + + public InfinityDataStorage() { + this(new ListTag(), new ListTag()); + } + + private InfinityDataStorage(ListTag keys, ListTag amounts) { + this.keys = keys; + this.amounts = amounts; + } + + /** + * 将当前数据封装为 CompoundTag 以写入存档 + */ + public CompoundTag serializeNBT() { + CompoundTag nbt = new CompoundTag(); + nbt.put("keys", keys); + nbt.put("amounts", amounts); + return nbt; + } + + /** + * 从存档读取数据并构造实例 + */ + public static InfinityDataStorage loadFromNBT(CompoundTag nbt) { + ListTag stackKeys = nbt.getList("keys", Tag.TAG_COMPOUND); + // amounts 以 CompoundTag 列表存储,每个 CompoundTag 内含 long 或 String + ListTag stackAmounts = nbt.getList("amounts", Tag.TAG_COMPOUND); + return new InfinityDataStorage(stackKeys, stackAmounts); + } +} diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java new file mode 100644 index 0000000..e24a5ab --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java @@ -0,0 +1,114 @@ +package com.extendedae_plus.util.storage; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.saveddata.SavedData; +import org.jetbrains.annotations.NotNull; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +/** + * InfinityStorageManager + *

+ * 世界级别的持久化容器,集中管理所有 InfinityBigInteger 存储单元的序列化数据。 + * 功能要点: + * - 在世界加载时从存档恢复所有 cell 的数据 + * - 提供按 UUID 获取/创建单个 cell 的数据容器 + * - 在世界保存时将内存数据打包为 NBT 写回存档 + */ +public class InfinityStorageManager extends SavedData { + + /** + * SavedData 文件名常量 + */ + public static final String FILE_NAME = "eap_infinity_biginteger_cells"; + /** + * 全局单例实例(在世界加载时由 InfiniteBigIntegerStorageCell.onLevelLoad 填充) + */ + public static InfinityStorageManager INSTANCE = null; + /** + * UUID -> 数据 的内存映射 + */ + private final Map cells = new HashMap<>(); + + public InfinityStorageManager() { + setDirty(); + } + + /** + * 从 NBT 构造:用于在世界加载时从存档恢复数据 + */ + public InfinityStorageManager(CompoundTag nbt) { + ListTag cellList = nbt.getList("list", CompoundTag.TAG_COMPOUND); + for (int i = 0; i < cellList.size(); i++) { + CompoundTag cell = cellList.getCompound(i); + cells.put(cell.getUUID("uuid"), InfinityDataStorage.loadFromNBT(cell.getCompound("data"))); + } + setDirty(); + } + + /** + * 根据给定的 ServerLevel 获取或创建该世界对应的 SavedData 实例并缓存到 INSTANCE + */ + public static InfinityStorageManager getForLevel(ServerLevel level) { + if (INSTANCE == null && level != null) { + INSTANCE = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME); + } + return INSTANCE; + } + + @Override + public @NotNull CompoundTag save(@NotNull CompoundTag nbt) { + // 将内存中的所有 cell 序列化为一个 ListTag + ListTag cellList = new ListTag(); + for (Map.Entry entry : cells.entrySet()) { + CompoundTag cell = new CompoundTag(); + cell.putUUID("uuid", entry.getKey()); + cell.put("data", entry.getValue().serializeNBT()); + cellList.add(cell); + } + nbt.put("list", cellList); + return nbt; + } + + /** + * 更新或添加某个 UUID 对应的数据并标记为脏(需要保存) + */ + public void updateCell(UUID uuid, InfinityDataStorage infinityDataStorage) { + cells.put(uuid, infinityDataStorage); + setDirty(); + } + + /** + * 获取或创建某个 UUID 对应的数据容器 + */ + public InfinityDataStorage getOrCreateCell(UUID uuid) { + if (!cells.containsKey(uuid)) { + updateCell(uuid, new InfinityDataStorage()); + } + return cells.get(uuid); + } + + /** + * 修改某个 UUID 对应的键与数量列表并保存(新的签名,stackAmounts 为 ListTag 字符串列表) + */ + public void modifyCell(UUID cellID, ListTag stackKeys, ListTag stackAmounts) { + InfinityDataStorage cellToModify = getOrCreateCell(cellID); + if (stackKeys != null && stackAmounts != null) { + cellToModify.keys = stackKeys; + cellToModify.amounts = stackAmounts; + } + updateCell(cellID, cellToModify); + } + + /** + * 删除某个 UUID 的持久化记录并标记为脏 + */ + public void removeCell(UUID uuid) { + cells.remove(uuid); + setDirty(); + } +} From 37d24334bb00dcc0051293b72188eb3262255192 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Tue, 16 Sep 2025 20:01:03 +0800 Subject: [PATCH 32/44] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20Infinity=20?= =?UTF-8?q?=E5=AD=98=E5=82=A8=EF=BC=9A=E7=A7=BB=E9=99=A4=E5=8F=AF=E5=8F=98?= =?UTF-8?q?=E5=85=B1=E4=BA=AB=20EMPTY=EF=BC=8C=E5=B0=81=E8=A3=85=20NBT=20?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=9B=E6=8C=89=E4=B8=96=E7=95=8C=E7=AE=A1?= =?UTF-8?q?=E7=90=86=20StorageManager=EF=BC=88=E7=A7=BB=E9=99=A4=E5=85=A8?= =?UTF-8?q?=E5=B1=80=20INSTANCE=EF=BC=89=EF=BC=9B=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E6=97=B6=E9=87=8D=E7=BD=AE=20totalStored=20=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=E9=87=8D=E5=A4=8D=E7=B4=AF=E8=AE=A1=EF=BC=9B=E7=94=A8=20Atomic?= =?UTF-8?q?Boolean=20=E4=BB=A3=E6=9B=BF=E9=98=9F=E5=88=97=20contains?= =?UTF-8?q?=EF=BC=8C=E4=BF=AE=E6=AD=A3=20persist=20=E7=9A=84=E7=A9=BA/?= =?UTF-8?q?=E6=97=A0=E7=AE=A1=E7=90=86=E5=99=A8=E5=A4=84=E7=90=86=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InfinityBigIntegerCellInventory.java | 49 ++++++++++++++----- .../util/storage/InfinityDataStorage.java | 32 ++++++++++-- .../util/storage/InfinityStorageManager.java | 36 +++++++++++--- 3 files changed, 93 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java index 19273c4..7e2216f 100644 --- a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -26,6 +26,7 @@ import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicBoolean; /** * InfinityBigIntegerCellInventory @@ -91,9 +92,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell { return null; } - // 获取全局存储实例 + // 获取全局存储实例(尽量安全地获取任意已注册的世界实例) private static InfinityStorageManager getStorageInstance() { - return InfinityStorageManager.INSTANCE; + return InfinityStorageManager.getAnyInstance(); } // 服务器 tick 回调:合并并执行待持久化项 @@ -133,10 +134,12 @@ public class InfinityBigIntegerCellInventory implements StorageCell { private InfinityDataStorage getCellStorage() { if (this.getUUID() == null) { // 如果没有UUID,返回空存储 - return InfinityDataStorage.EMPTY; + return InfinityDataStorage.empty(); } else { - // 否则获取或创建对应UUID的存储 - return getStorageInstance().getOrCreateCell(getUUID()); + // 否则获取或创建对应UUID的存储,若管理器不可用则返回空存储以避免 NPE + InfinityStorageManager mgr = getStorageInstance(); + if (mgr == null) return InfinityDataStorage.empty(); + return mgr.getOrCreateCell(getUUID()); } } @@ -187,8 +190,11 @@ public class InfinityBigIntegerCellInventory implements StorageCell { private void loadCellStoredMap() { boolean corruptedTag = false; // 标记数据是否损坏 if (!stack.hasTag()) return; - ListTag keys = this.getCellStorage().keys; - ListTag amounts = this.getCellStorage().amounts; + // 在加载前重置缓存,避免重复累计 + totalStored = BigInteger.ZERO; + InfinityDataStorage storage = this.getCellStorage(); + ListTag keys = storage.getKeys(); + ListTag amounts = storage.getAmounts(); int len = Math.min(keys.size(), amounts.size()); for (int i = 0; i < len; i++) { AEKey key = AEKey.fromTagGeneric(keys.getCompound(i)); @@ -223,6 +229,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } // 标记数据需要保存,并通知容器或直接持久化 + private final AtomicBoolean queued = new AtomicBoolean(false); + private void saveChanges() { // 标记为未持久化,交由容器或延迟任务合并写入以减少 I/O isPersisted = false; @@ -231,7 +239,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell { container.saveChanges(); } else { // 如果没有容器,入队等待服务器 tick 在主线程统一持久化,避免频繁 I/O - if (!PENDING_PERSIST.contains(this)) { + if (queued.compareAndSet(false, true)) { PENDING_PERSIST.offer(this); } } @@ -258,13 +266,21 @@ public class InfinityBigIntegerCellInventory implements StorageCell { if (map.isEmpty()) { // 如果存储为空,移除UUID和全局存储中的数据 if (this.hasUUID()) { - getStorageInstance().removeCell(getUUID()); + InfinityStorageManager mgr = getStorageInstance(); + if (mgr != null) mgr.removeCell(getUUID()); if (stack.getTag() != null) { stack.getTag().remove("uuid"); // 移除缓存的 total 字段 stack.getTag().remove("total"); } + // 清理 queued 标志并标记已持久化 + queued.set(false); + isPersisted = true; + return; } + // 无 UUID 且为空,不需要做额外操作,但确保已标记为已持久化 + queued.set(false); + isPersisted = true; return; } // 构建要保存的Key和数量列表(混合表示:long 或 string) @@ -284,11 +300,16 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } } // 如果没有Key,更新为空存储,否则保存数据 - if (keys.isEmpty()) { - getStorageInstance().updateCell(this.getUUID(), new InfinityDataStorage()); + InfinityStorageManager mgr = getStorageInstance(); + if (mgr == null) { + // 无可用存储管理器,跳过持久化(保留内存状态) } else { - // amounts 现在为 CompoundTag 列表 - getStorageInstance().modifyCell(this.getUUID(), keys, amountTags); + if (keys.isEmpty()) { + mgr.updateCell(this.getUUID(), new InfinityDataStorage()); + } else { + // amounts 现在为 CompoundTag 列表 + mgr.modifyCell(this.getUUID(), keys, amountTags); + } } // 将缓存的 totalStored 同步到 ItemStack 的 NBT,优先使用 long if (stack.getOrCreateTag() != null) { @@ -299,6 +320,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } } isPersisted = true; + // 持久化完成后,清除 queued 标志 + queued.set(false); } // 插入物品到存储单元 diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java index 4ef9036..0a44d87 100644 --- a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java @@ -18,17 +18,17 @@ import net.minecraft.nbt.Tag; */ public class InfinityDataStorage { - /** 空实例(表示没有数据) */ - public static final InfinityDataStorage EMPTY = new InfinityDataStorage(); + // 不再暴露可变的共享实例,避免多个调用方修改同一 ListTag 导致交叉污染 + private static final InfinityDataStorage TRUE_EMPTY = new InfinityDataStorage(new ListTag(), new ListTag()); /** 序列化的键列表(NBT ListTag,元素为 CompoundTag) */ - public ListTag keys; + private ListTag keys; /** * 与 keys 对应的数量列表(NBT ListTag,元素为 CompoundTag): * - 若数量能放入 long,则 CompoundTag 包含键 "l"(long) * - 否则包含键 "s"(String) 存放 BigInteger 的字符串形式 */ - public ListTag amounts; + private ListTag amounts; public InfinityDataStorage() { this(new ListTag(), new ListTag()); @@ -39,6 +39,14 @@ public class InfinityDataStorage { this.amounts = amounts; } + /** + * 返回一个空的不可共享实例(调用方若需要可变副本请自行复制) + */ + public static InfinityDataStorage empty() { + // 返回一个新的实例以避免共享可变对象被篡改 + return new InfinityDataStorage(new ListTag(), new ListTag()); + } + /** * 将当前数据封装为 CompoundTag 以写入存档 */ @@ -58,4 +66,20 @@ public class InfinityDataStorage { ListTag stackAmounts = nbt.getList("amounts", Tag.TAG_COMPOUND); return new InfinityDataStorage(stackKeys, stackAmounts); } + + public ListTag getKeys() { + return keys; + } + + public ListTag getAmounts() { + return amounts; + } + + public void setKeys(ListTag keys) { + this.keys = keys; + } + + public void setAmounts(ListTag amounts) { + this.amounts = amounts; + } } diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java index e24a5ab..1b36fbd 100644 --- a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java @@ -2,13 +2,16 @@ package com.extendedae_plus.util.storage; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; +import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; import net.minecraft.world.level.saveddata.SavedData; import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; /** * InfinityStorageManager @@ -26,9 +29,9 @@ public class InfinityStorageManager extends SavedData { */ public static final String FILE_NAME = "eap_infinity_biginteger_cells"; /** - * 全局单例实例(在世界加载时由 InfiniteBigIntegerStorageCell.onLevelLoad 填充) + * Per-world instances to avoid cross-world leakage. Keyed by world ResourceKey. */ - public static InfinityStorageManager INSTANCE = null; + private static final Map, InfinityStorageManager> INSTANCES = new ConcurrentHashMap<>(); /** * UUID -> 数据 的内存映射 */ @@ -54,10 +57,29 @@ public class InfinityStorageManager extends SavedData { * 根据给定的 ServerLevel 获取或创建该世界对应的 SavedData 实例并缓存到 INSTANCE */ public static InfinityStorageManager getForLevel(ServerLevel level) { - if (INSTANCE == null && level != null) { - INSTANCE = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME); + if (level == null) return null; + ResourceKey key = level.dimension(); + InfinityStorageManager mgr = INSTANCES.get(key); + if (mgr == null) { + mgr = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME); + INSTANCES.put(key, mgr); } - return INSTANCE; + return mgr; + } + + /** + * 返回任何现有实例,作为无法访问 ServerLevel 的代码路径的安全回退。 + */ + public static InfinityStorageManager getAnyInstance() { + return INSTANCES.values().stream().findFirst().orElse(null); + } + + /** + * 删除世界的实例(在世界卸载时调用) + */ + public static void removeForLevel(ServerLevel level) { + if (level == null) return; + INSTANCES.remove(level.dimension()); } @Override @@ -98,8 +120,8 @@ public class InfinityStorageManager extends SavedData { public void modifyCell(UUID cellID, ListTag stackKeys, ListTag stackAmounts) { InfinityDataStorage cellToModify = getOrCreateCell(cellID); if (stackKeys != null && stackAmounts != null) { - cellToModify.keys = stackKeys; - cellToModify.amounts = stackAmounts; + cellToModify.setKeys(stackKeys); + cellToModify.setAmounts(stackAmounts); } updateCell(cellID, cellToModify); } From 3039add611562c1338c238c35052e903092ce4ba Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Tue, 16 Sep 2025 21:43:03 +0800 Subject: [PATCH 33/44] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=97=A0?= =?UTF-8?q?=E9=99=90=E5=AD=98=E5=82=A8=E5=85=83=E4=BB=B6=E5=9B=BE=E6=A0=87?= =?UTF-8?q?=E3=80=81=E9=85=8D=E6=96=B9=E7=AD=89=E5=86=85=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae/items/InfinityBigIntegerCellItem.java | 2 ++ .../extendedae_plus/init/ModCreativeTabs.java | 2 +- .../com/extendedae_plus/init/ModItems.java | 4 ++-- .../assets/extendedae_plus/lang/en_us.json | 2 ++ .../assets/extendedae_plus/lang/zh_cn.json | 2 ++ .../models/item/infinity_biginteger_cell.json | 8 ++++++++ .../item/infinity_biginteger_cell.png | Bin 0 -> 2266 bytes .../recipes/infinity_biginteger_cell.json | 18 ++++++++++++++++++ 8 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/main/resources/assets/extendedae_plus/models/item/infinity_biginteger_cell.json create mode 100644 src/main/resources/assets/extendedae_plus/textures/item/infinity_biginteger_cell.png create mode 100644 src/main/resources/data/extendedae_plus/recipes/infinity_biginteger_cell.json diff --git a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java index 5b550a1..7cfb313 100644 --- a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java +++ b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java @@ -36,6 +36,8 @@ public class InfinityBigIntegerCellItem extends Item { @Nullable Level world, @NotNull List tooltip, @NotNull TooltipFlag context) { + tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon")); + Preconditions.checkArgument(stack.getItem() == this); // 仅在 ItemStack 自身存在 UUID 时显示 UUID,避免触发持久化或加载逻辑 CompoundTag tag = stack.getTag(); diff --git a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java index dc4a03c..f30b2d6 100644 --- a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java +++ b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java @@ -34,7 +34,7 @@ public final class ModCreativeTabs { output.accept(ModItems.createEntitySpeedCardStack(8)); output.accept(ModItems.createEntitySpeedCardStack(16)); - output.accept(ModItems.INFINITY_BIGINT_ITEM_CELL.get()); + output.accept(ModItems.INFINITY_BIGINTEGER_CELL_ITEM.get()); }) .build()); } diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index fc6a2e5..6ec6a70 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -66,8 +66,8 @@ public final class ModItems { () -> new EntitySpeedCardItem(new Item.Properties()) ); - public static final RegistryObject INFINITY_BIGINT_ITEM_CELL = ITEMS.register( - "infinity_item_cell", InfinityBigIntegerCellItem::new + public static final RegistryObject INFINITY_BIGINTEGER_CELL_ITEM = ITEMS.register( + "infinity_biginteger_cell", InfinityBigIntegerCellItem::new ); diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 230dade..8ae2ff7 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -22,6 +22,8 @@ "item.extendedae_plus.entity_speed_card.x4": "Entity Acceleration Card (x4)", "item.extendedae_plus.entity_speed_card.x8": "Entity Acceleration Card (x8)", "item.extendedae_plus.entity_speed_card.x16": "Entity Acceleration Card (x16)", + "item.extendedae_plus.infinity_biginteger_cell": "§cI§6n§ef§ai§bn§di§9t§fy §cS§6t§eo§ar§ba§dg§9e §fC§co§6m§ep§ao§bn§de§9n§ft", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon": "§7Through the sacrifice of nine rare materials, you summon Iava, who bestows upon the summoner an §cI§6n§ef§ai§bn§di§9t§fy §cS§6t§eo§ar§ba§dg§9e §fC§co§6m§ep§ao§bn§de§9n§ft§7 forged from the endless void.", "tooltip.extendedae_plus.entity_speed_card.multiplier": "Multiplier: %s", "tooltip.extendedae_plus.entity_speed_card.max": "Max effective: %s x", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index dd25863..b5f663b 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -22,6 +22,8 @@ "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", "item.extendedae_plus.entity_speed_card.x8": "实体加速卡 (x8)", "item.extendedae_plus.entity_speed_card.x16": "实体加速卡 (x16)", + "item.extendedae_plus.infinity_biginteger_cell": "§c无§6限§e存§a储§b元§d件", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon": "§7以九种稀有材料为祭,唤出 Iava;其将一枚 §c无§6限§e存§a储§b元§d件 §7赐予召唤者,源自无尽虚空。", "tooltip.extendedae_plus.entity_speed_card.multiplier": "乘数: %s", "tooltip.extendedae_plus.entity_speed_card.max": "最大生效: %s 倍", diff --git a/src/main/resources/assets/extendedae_plus/models/item/infinity_biginteger_cell.json b/src/main/resources/assets/extendedae_plus/models/item/infinity_biginteger_cell.json new file mode 100644 index 0000000..235c138 --- /dev/null +++ b/src/main/resources/assets/extendedae_plus/models/item/infinity_biginteger_cell.json @@ -0,0 +1,8 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "extendedae_plus:item/infinity_biginteger_cell" + } +} + + diff --git a/src/main/resources/assets/extendedae_plus/textures/item/infinity_biginteger_cell.png b/src/main/resources/assets/extendedae_plus/textures/item/infinity_biginteger_cell.png new file mode 100644 index 0000000000000000000000000000000000000000..5c47ca4fdedf33c73a8afa63e5c1fe41f4978db7 GIT binary patch literal 2266 zcmcgueNYr-99|d)5hWog8wPb}Q}ctpyWQKp+uJx1Iq)zJ5GcSgb8q)O?)2_<-Cf`y zrqGNeq%2eOqiIT;v`;ll#}dgAF`Ud8ok%OgR2-eeufnvbcaP)320z9>x|zLw_uc1x zp6BJhA1G3_uoqzvHp z*sEnwSe;wMS1;f#0+u!vO%1S+zz0+g4fwo%g$-D-ATJBY+O!@+gAjFr6-(Cy(Go{K znjy*nwde?(HyB9NY|)t+r`cp=Qc%)B(s~1_CkULdu!Mm%Flgw9K{;7)u?4oQkQltO zVs2HHSiQcovQk%R)QNJLp0HRf8V5<@5P>UIew7R0e&ykQ1{+X#*(0eQ(T{43oKq}U ztr)c07lTg<)B2TAo?yoG0Z!5rI)fHd5Ge3roK!A*gW>|O2VURKx6lTH0t`))S~mw9gtdDVSh}jv^HB&E zhDKfw8te&{M1S3f?W+&4h`atW0Hsifm52b~7bN(^_ zcTPQa@4?(%U-r5DAA`|r`(Hph&!FvPtR#?d36x^`2Vfa-6FTyVy;D>pV;j2Vh zH+?vQM4ZdEr57=c@2p63C(KH2P184;M$1Q%N4f1AIv?D;eDat33*#Q$^klQPqsB=j@t2le0pTmq^P9W`ZM0yc}eTAs@x`N?y(kg?@v89 zs?wg>)16Q-v$t#MkGec5FY?cg*{__pe%d*=WrTTr^YiuD*MA|7HBRVRy?i(N_UcQQ z_bq#G_YXS{b{?WGb;Rvh<^QB@eKb-*MxMRmY3n+%aDH>tytghM7#crx=VUSGo0GeA z-|oIqlT|D1-#9zv2KvX|NcwUlI^<{OzB&$(To+@m*Q^!xk6S}Lu&?Iz)4zS3iu~R& zBC4<;;{KHpV})z&CG)nlcF#FwKaq&kani3>Q<7RY9-H1(8r!x0IZ#TiEw|;)Xe!M( zrPhrcQ;=2L+AuPa8Ij+9ZdqW$(MQGx*txCSQs#V@c}hi^jy{H@G*!o+%|XU(IsKLU zrFe1a{H-}pr`CbenOA#SV&07C$cw4%N$oy^F2Y}aan`mswlDU!(NjMxK76r4mig??bH%wcSIOZT0_w|s^mL;@A$L<|df4n!M zxj1S2wdmSb*=%3586gg}C2m-<=n_OJ*GG0{uI;1g^A`UDbnOYi literal 0 HcmV?d00001 diff --git a/src/main/resources/data/extendedae_plus/recipes/infinity_biginteger_cell.json b/src/main/resources/data/extendedae_plus/recipes/infinity_biginteger_cell.json new file mode 100644 index 0000000..a05271b --- /dev/null +++ b/src/main/resources/data/extendedae_plus/recipes/infinity_biginteger_cell.json @@ -0,0 +1,18 @@ +{ + "type": "minecraft:crafting_shapeless", + "ingredients": [ + { "item": "minecraft:turtle_helmet" }, + { "item": "minecraft:dragon_head" }, + { "item": "minecraft:totem_of_undying" }, + { "item": "minecraft:echo_shard" }, + { "item": "ae2:cell_component_256k" }, + { "item": "minecraft:heart_of_the_sea" }, + { "item": "minecraft:nether_star" }, + { "item": "minecraft:netherite_block" }, + { "item": "minecraft:enchanted_golden_apple" } + ], + "result": { + "item": "extendedae_plus:infinity_biginteger_cell", + "count": 1 + } +} \ No newline at end of file From d316c5f0393bfd148349c72277c5e3fa5f8b40e0 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Tue, 16 Sep 2025 22:02:13 +0800 Subject: [PATCH 34/44] =?UTF-8?q?fix=EF=BC=9A=E5=9B=9E=E9=80=80=E6=97=A0?= =?UTF-8?q?=E9=99=90=E5=AD=98=E5=82=A8=E5=85=83=E4=BB=B6=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InfinityBigIntegerCellInventory.java | 49 +++++-------------- .../util/storage/InfinityDataStorage.java | 32 ++---------- .../util/storage/InfinityStorageManager.java | 36 +++----------- 3 files changed, 24 insertions(+), 93 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java index 7e2216f..19273c4 100644 --- a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -26,7 +26,6 @@ import java.math.RoundingMode; import java.text.DecimalFormat; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicBoolean; /** * InfinityBigIntegerCellInventory @@ -92,9 +91,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell { return null; } - // 获取全局存储实例(尽量安全地获取任意已注册的世界实例) + // 获取全局存储实例 private static InfinityStorageManager getStorageInstance() { - return InfinityStorageManager.getAnyInstance(); + return InfinityStorageManager.INSTANCE; } // 服务器 tick 回调:合并并执行待持久化项 @@ -134,12 +133,10 @@ public class InfinityBigIntegerCellInventory implements StorageCell { private InfinityDataStorage getCellStorage() { if (this.getUUID() == null) { // 如果没有UUID,返回空存储 - return InfinityDataStorage.empty(); + return InfinityDataStorage.EMPTY; } else { - // 否则获取或创建对应UUID的存储,若管理器不可用则返回空存储以避免 NPE - InfinityStorageManager mgr = getStorageInstance(); - if (mgr == null) return InfinityDataStorage.empty(); - return mgr.getOrCreateCell(getUUID()); + // 否则获取或创建对应UUID的存储 + return getStorageInstance().getOrCreateCell(getUUID()); } } @@ -190,11 +187,8 @@ public class InfinityBigIntegerCellInventory implements StorageCell { private void loadCellStoredMap() { boolean corruptedTag = false; // 标记数据是否损坏 if (!stack.hasTag()) return; - // 在加载前重置缓存,避免重复累计 - totalStored = BigInteger.ZERO; - InfinityDataStorage storage = this.getCellStorage(); - ListTag keys = storage.getKeys(); - ListTag amounts = storage.getAmounts(); + ListTag keys = this.getCellStorage().keys; + ListTag amounts = this.getCellStorage().amounts; int len = Math.min(keys.size(), amounts.size()); for (int i = 0; i < len; i++) { AEKey key = AEKey.fromTagGeneric(keys.getCompound(i)); @@ -229,8 +223,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } // 标记数据需要保存,并通知容器或直接持久化 - private final AtomicBoolean queued = new AtomicBoolean(false); - private void saveChanges() { // 标记为未持久化,交由容器或延迟任务合并写入以减少 I/O isPersisted = false; @@ -239,7 +231,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell { container.saveChanges(); } else { // 如果没有容器,入队等待服务器 tick 在主线程统一持久化,避免频繁 I/O - if (queued.compareAndSet(false, true)) { + if (!PENDING_PERSIST.contains(this)) { PENDING_PERSIST.offer(this); } } @@ -266,21 +258,13 @@ public class InfinityBigIntegerCellInventory implements StorageCell { if (map.isEmpty()) { // 如果存储为空,移除UUID和全局存储中的数据 if (this.hasUUID()) { - InfinityStorageManager mgr = getStorageInstance(); - if (mgr != null) mgr.removeCell(getUUID()); + getStorageInstance().removeCell(getUUID()); if (stack.getTag() != null) { stack.getTag().remove("uuid"); // 移除缓存的 total 字段 stack.getTag().remove("total"); } - // 清理 queued 标志并标记已持久化 - queued.set(false); - isPersisted = true; - return; } - // 无 UUID 且为空,不需要做额外操作,但确保已标记为已持久化 - queued.set(false); - isPersisted = true; return; } // 构建要保存的Key和数量列表(混合表示:long 或 string) @@ -300,16 +284,11 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } } // 如果没有Key,更新为空存储,否则保存数据 - InfinityStorageManager mgr = getStorageInstance(); - if (mgr == null) { - // 无可用存储管理器,跳过持久化(保留内存状态) + if (keys.isEmpty()) { + getStorageInstance().updateCell(this.getUUID(), new InfinityDataStorage()); } else { - if (keys.isEmpty()) { - mgr.updateCell(this.getUUID(), new InfinityDataStorage()); - } else { - // amounts 现在为 CompoundTag 列表 - mgr.modifyCell(this.getUUID(), keys, amountTags); - } + // amounts 现在为 CompoundTag 列表 + getStorageInstance().modifyCell(this.getUUID(), keys, amountTags); } // 将缓存的 totalStored 同步到 ItemStack 的 NBT,优先使用 long if (stack.getOrCreateTag() != null) { @@ -320,8 +299,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } } isPersisted = true; - // 持久化完成后,清除 queued 标志 - queued.set(false); } // 插入物品到存储单元 diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java index 0a44d87..4ef9036 100644 --- a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java @@ -18,17 +18,17 @@ import net.minecraft.nbt.Tag; */ public class InfinityDataStorage { - // 不再暴露可变的共享实例,避免多个调用方修改同一 ListTag 导致交叉污染 - private static final InfinityDataStorage TRUE_EMPTY = new InfinityDataStorage(new ListTag(), new ListTag()); + /** 空实例(表示没有数据) */ + public static final InfinityDataStorage EMPTY = new InfinityDataStorage(); /** 序列化的键列表(NBT ListTag,元素为 CompoundTag) */ - private ListTag keys; + public ListTag keys; /** * 与 keys 对应的数量列表(NBT ListTag,元素为 CompoundTag): * - 若数量能放入 long,则 CompoundTag 包含键 "l"(long) * - 否则包含键 "s"(String) 存放 BigInteger 的字符串形式 */ - private ListTag amounts; + public ListTag amounts; public InfinityDataStorage() { this(new ListTag(), new ListTag()); @@ -39,14 +39,6 @@ public class InfinityDataStorage { this.amounts = amounts; } - /** - * 返回一个空的不可共享实例(调用方若需要可变副本请自行复制) - */ - public static InfinityDataStorage empty() { - // 返回一个新的实例以避免共享可变对象被篡改 - return new InfinityDataStorage(new ListTag(), new ListTag()); - } - /** * 将当前数据封装为 CompoundTag 以写入存档 */ @@ -66,20 +58,4 @@ public class InfinityDataStorage { ListTag stackAmounts = nbt.getList("amounts", Tag.TAG_COMPOUND); return new InfinityDataStorage(stackKeys, stackAmounts); } - - public ListTag getKeys() { - return keys; - } - - public ListTag getAmounts() { - return amounts; - } - - public void setKeys(ListTag keys) { - this.keys = keys; - } - - public void setAmounts(ListTag amounts) { - this.amounts = amounts; - } } diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java index 1b36fbd..e24a5ab 100644 --- a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java @@ -2,16 +2,13 @@ package com.extendedae_plus.util.storage; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; -import net.minecraft.resources.ResourceKey; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.Level; import net.minecraft.world.level.saveddata.SavedData; import org.jetbrains.annotations.NotNull; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; /** * InfinityStorageManager @@ -29,9 +26,9 @@ public class InfinityStorageManager extends SavedData { */ public static final String FILE_NAME = "eap_infinity_biginteger_cells"; /** - * Per-world instances to avoid cross-world leakage. Keyed by world ResourceKey. + * 全局单例实例(在世界加载时由 InfiniteBigIntegerStorageCell.onLevelLoad 填充) */ - private static final Map, InfinityStorageManager> INSTANCES = new ConcurrentHashMap<>(); + public static InfinityStorageManager INSTANCE = null; /** * UUID -> 数据 的内存映射 */ @@ -57,29 +54,10 @@ public class InfinityStorageManager extends SavedData { * 根据给定的 ServerLevel 获取或创建该世界对应的 SavedData 实例并缓存到 INSTANCE */ public static InfinityStorageManager getForLevel(ServerLevel level) { - if (level == null) return null; - ResourceKey key = level.dimension(); - InfinityStorageManager mgr = INSTANCES.get(key); - if (mgr == null) { - mgr = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME); - INSTANCES.put(key, mgr); + if (INSTANCE == null && level != null) { + INSTANCE = level.getDataStorage().computeIfAbsent(InfinityStorageManager::new, InfinityStorageManager::new, FILE_NAME); } - return mgr; - } - - /** - * 返回任何现有实例,作为无法访问 ServerLevel 的代码路径的安全回退。 - */ - public static InfinityStorageManager getAnyInstance() { - return INSTANCES.values().stream().findFirst().orElse(null); - } - - /** - * 删除世界的实例(在世界卸载时调用) - */ - public static void removeForLevel(ServerLevel level) { - if (level == null) return; - INSTANCES.remove(level.dimension()); + return INSTANCE; } @Override @@ -120,8 +98,8 @@ public class InfinityStorageManager extends SavedData { public void modifyCell(UUID cellID, ListTag stackKeys, ListTag stackAmounts) { InfinityDataStorage cellToModify = getOrCreateCell(cellID); if (stackKeys != null && stackAmounts != null) { - cellToModify.setKeys(stackKeys); - cellToModify.setAmounts(stackAmounts); + cellToModify.keys = stackKeys; + cellToModify.amounts = stackAmounts; } updateCell(cellID, cellToModify); } From fb8db3693b1185a7ad0d0369ee0b543e6deea3a3 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Wed, 17 Sep 2025 15:14:10 +0800 Subject: [PATCH 35/44] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=97=A0?= =?UTF-8?q?=E7=BA=BF=E5=AD=98=E5=82=A8=E5=85=83=E4=BB=B6=E7=9A=84=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E7=A7=8D=E7=B1=BB=E6=95=B0=E9=87=8F=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=EF=BC=9B=E4=BF=AE=E6=94=B9=E5=90=8D=E5=AD=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../storage/InfinityBigIntegerCellInventory.java | 3 +++ .../ae/items/InfinityBigIntegerCellItem.java | 14 +++++++++++++- .../assets/extendedae_plus/lang/en_us.json | 3 ++- .../assets/extendedae_plus/lang/zh_cn.json | 5 +++-- 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java index 19273c4..8642326 100644 --- a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -297,6 +297,9 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } else { stack.getOrCreateTag().putString("total", totalStored.toString()); } + // 将当前已存储的不同物品种类数缓存到 NBT(键名: "types"),用于客户端 tooltip 显示 + int typesCount = this.getCellStoredMap().size(); + stack.getOrCreateTag().putInt("types", typesCount); } isPersisted = true; } diff --git a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java index 7cfb313..dde5b96 100644 --- a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java +++ b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java @@ -36,7 +36,8 @@ public class InfinityBigIntegerCellItem extends Item { @Nullable Level world, @NotNull List tooltip, @NotNull TooltipFlag context) { - tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon")); + tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon1")); + tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon2")); Preconditions.checkArgument(stack.getItem() == this); // 仅在 ItemStack 自身存在 UUID 时显示 UUID,避免触发持久化或加载逻辑 @@ -46,6 +47,17 @@ public class InfinityBigIntegerCellItem extends Item { tooltip.add( Component.literal("UUID: ").withStyle(ChatFormatting.GRAY).append(Component.literal(uuidStr).withStyle(ChatFormatting.YELLOW)) ); + // 读取并显示已缓存的种类数量(types),表示当前存储了多少种不同的 AEKey + if (tag.contains("types")) { + try { + int types = tag.getInt("types"); + tooltip.add( + Component.literal("Types: ").withStyle(ChatFormatting.GRAY).append(Component.literal(String.valueOf(types)).withStyle(ChatFormatting.GREEN)) + ); + } catch (Exception ignored) { + // ignore malformed value + } + } // 读取并显示已缓存的 total(支持 long 或 string),使用格式化函数展示友好单位 if (tag.contains("total")) { BigInteger total = BigInteger.ZERO; diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 8ae2ff7..1245bae 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -23,7 +23,8 @@ "item.extendedae_plus.entity_speed_card.x8": "Entity Acceleration Card (x8)", "item.extendedae_plus.entity_speed_card.x16": "Entity Acceleration Card (x16)", "item.extendedae_plus.infinity_biginteger_cell": "§cI§6n§ef§ai§bn§di§9t§fy §cS§6t§eo§ar§ba§dg§9e §fC§co§6m§ep§ao§bn§de§9n§ft", - "tooltip.extendedae_plus.infinity_biginteger_cell.summon": "§7Through the sacrifice of nine rare materials, you summon Iava, who bestows upon the summoner an §cI§6n§ef§ai§bn§di§9t§fy §cS§6t§eo§ar§ba§dg§9e §fC§co§6m§ep§ao§bn§de§9n§ft§7 forged from the endless void.", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "§7Through the sacrifice of nine rare materials, you summon Iava, who grants the summoner an §4all-consuming§csilence§6.", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b——§4Within §ca §6small §espace§a, §bthere §dare §4a §cthousand §6realms", "tooltip.extendedae_plus.entity_speed_card.multiplier": "Multiplier: %s", "tooltip.extendedae_plus.entity_speed_card.max": "Max effective: %s x", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index b5f663b..7f94f24 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -22,8 +22,9 @@ "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", "item.extendedae_plus.entity_speed_card.x8": "实体加速卡 (x8)", "item.extendedae_plus.entity_speed_card.x16": "实体加速卡 (x16)", - "item.extendedae_plus.infinity_biginteger_cell": "§c无§6限§e存§a储§b元§d件", - "tooltip.extendedae_plus.infinity_biginteger_cell.summon": "§7以九种稀有材料为祭,唤出 Iava;其将一枚 §c无§6限§e存§a储§b元§d件 §7赐予召唤者,源自无尽虚空。", + "item.extendedae_plus.infinity_biginteger_cell": "§4吞§c噬§6万§e物§a的§b寂§d静", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "九重献祭, 终得虚空回响——觐见虚空之主Iava, 赐汝§4吞§c噬§6万§e籁§a的§b寂§d静", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b——§4方§c寸§6之§e间§a, §b自§d有§4千§c寰", "tooltip.extendedae_plus.entity_speed_card.multiplier": "乘数: %s", "tooltip.extendedae_plus.entity_speed_card.max": "最大生效: %s 倍", From 01e77aff08aeebe7df4778e3ae300b001a430640 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Wed, 17 Sep 2025 18:14:36 +0800 Subject: [PATCH 36/44] 1.4.2-beta --- CHANGELOG.md | 47 +++++++++++++++++++ gradle.properties | 2 +- .../assets/extendedae_plus/lang/en_us.json | 6 +-- .../assets/extendedae_plus/lang/zh_cn.json | 6 +-- 4 files changed, 54 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa268f8..a056e01 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,53 @@ ## [Unreleased] / [未发布] +## [1.4.2] / [未发布] +### Added / 新增 +- 添加实体加速器,最高可加速 1024 倍(配置文件可配置能耗、黑名单、额外消耗倍率名单) + - Added Entity Accelerator block, capable of up to 1024× acceleration (configurable energy cost, blacklist, and extra consumption multiplier list). +- 添加实体加速卡系列,用于设置实体加速器加速倍率 + - Added Entity Acceleration Card series to configure acceleration multiplier for the Entity Accelerator. +- 添加物品“吞噬万籁的寂静”,可存储 21 亿种不同的资源,每种资源存储数量无上限(气体等物品须安装对应附属 mod) + - Added item “Devourer of Cosmic Silence”: stores up to 2.1 billion distinct resources with unlimited quantity per type (gases and other types require respective addon mods). +- eae扩展样板管理界面添加F键搜索支持 + - Added F-key search support in Extended Pattern Management Terminal. +- 合成计划界面支持 Shift+点击取消自动添加缺失材料至 JEI 书签 + - Crafting Plan GUI: Shift-clicking cancel button auto-adds missing ingredients to JEI bookmarks. +- AE 合成暂停检查阈值配置项(默认值 100000) + - Added config option for AE crafting pause threshold (default: 100000). +- 智能系列支持高级 AE 供应器 + - Smart series now supports Advanced AE Providers. +- 无线收发器支持重命名,Jade 可以在从节点显示主节点名称 + - Wireless Repeater supports renaming; Jade HUD displays master node name on slave terminals. +- 智能阻挡开启时自动启用原版阻挡 + - Enabling Smart Blocking now also activates Vanilla Blocking automatically. +- 调整样板制作数量显示上限 + - Adjusted display limit for pattern output quantity. +- 放宽扩展供应器样板手动倍增限制 + - Relaxed manual doubling restrictions for Extended Providers. +### Fixed / 修复 +- 修复无线收发器频道限制与渲染问题 + - Fixed channel limit and rendering issues for Wireless Repeater. + +## [1.4.1] +### Added / 新增 +- 模组配置项:可设置智能倍增的最大倍数 + - Config option: set maximum multiplier for Smart Doubling. +- 上传样板搜索框:右键点击可清空文本 + - Right-clicking the pattern upload search box clears the text. +- 合成监控界面:打开样板供应器 UI 时自动跳转到该样板所在页数,并以彩虹高亮显示 + - Crafting monitor: auto-jumps to the page containing the pattern and highlights it with rainbow effect when opening the provider UI. +- 样板供应器 UI 标题现在显示为玩家自定义名称 + - Pattern Provider UI now displays the player-customized name as its title. +- 配置项:当产物数量达到指定值时启用智能倍增 + - Config option: enable Smart Doubling only when output amount reaches a specified threshold. + +### Fixed / 修复 +- 修复编码终端中空白配方无法覆盖已有编码样板的问题 + - Fixed issue where blank recipes couldn't overwrite existing encoded patterns in the Encoding Terminal. +- 修复非 AE 与 ExtendedAE 样板供应器无法发配材料的问题 + - Fixed issue where non-AE2 and non-ExtendedAE pattern providers failed to dispatch materials. + ## [1.4.0-fix] ### Added / 新增 - JEI 书签优先用于编码样板匹配(书签越靠前,匹配优先级越高) diff --git a/gradle.properties b/gradle.properties index 2524cfb..d7ffbbb 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.4.1-entitySpeedTicker +mod_version = 1.4.2-beta maven_group = com.extendedae_plus archives_name = extendedae_plus diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 1245bae..2187081 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -22,9 +22,9 @@ "item.extendedae_plus.entity_speed_card.x4": "Entity Acceleration Card (x4)", "item.extendedae_plus.entity_speed_card.x8": "Entity Acceleration Card (x8)", "item.extendedae_plus.entity_speed_card.x16": "Entity Acceleration Card (x16)", - "item.extendedae_plus.infinity_biginteger_cell": "§cI§6n§ef§ai§bn§di§9t§fy §cS§6t§eo§ar§ba§dg§9e §fC§co§6m§ep§ao§bn§de§9n§ft", - "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "§7Through the sacrifice of nine rare materials, you summon Iava, who grants the summoner an §4all-consuming§csilence§6.", - "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b——§4Within §ca §6small §espace§a, §bthere §dare §4a §cthousand §6realms", + "item.extendedae_plus.infinity_biginteger_cell": "§4De§cvou§6rer §eof §aCo§bsmic §dSilence", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "§6Through ninefold sacrifice, the Void echoes§r—§8Iava, Lord of the Void§r, bestows upon thee this artifact", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b—§4A §dUni§cverse §eWith§ain §6A §bSin§5gle §9Point", "tooltip.extendedae_plus.entity_speed_card.multiplier": "Multiplier: %s", "tooltip.extendedae_plus.entity_speed_card.max": "Max effective: %s x", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 7f94f24..d89594e 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -22,9 +22,9 @@ "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", "item.extendedae_plus.entity_speed_card.x8": "实体加速卡 (x8)", "item.extendedae_plus.entity_speed_card.x16": "实体加速卡 (x16)", - "item.extendedae_plus.infinity_biginteger_cell": "§4吞§c噬§6万§e物§a的§b寂§d静", - "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "九重献祭, 终得虚空回响——觐见虚空之主Iava, 赐汝§4吞§c噬§6万§e籁§a的§b寂§d静", - "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b——§4方§c寸§6之§e间§a, §b自§d有§4千§c寰", + "item.extendedae_plus.infinity_biginteger_cell": "§4吞§c噬§6万§e籁§a的§b寂§d静", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "§6九重献祭, 终得虚空回响§r——觐见§8虚空之主Iava§r, 赐汝此物", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b——§4方§d寸§c之§e间§a, §6自§b有§5千§9寰", "tooltip.extendedae_plus.entity_speed_card.multiplier": "乘数: %s", "tooltip.extendedae_plus.entity_speed_card.max": "最大生效: %s 倍", From ef83089dc38b25305a3a0a1a0c382ce8f128f6b5 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 18 Sep 2025 00:04:25 +0800 Subject: [PATCH 37/44] =?UTF-8?q?fix:=20=E6=97=A0=E7=BA=BF=E5=AD=98?= =?UTF-8?q?=E5=82=A8=E5=85=83=E4=BB=B6=E4=BD=BF=E7=94=A8=E9=A5=B1=E5=92=8C?= =?UTF-8?q?=20BigInteger=20=E7=B4=AF=E5=8A=A0=EF=BC=8C=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=20long=20=E6=BA=A2=E5=87=BA=E5=AF=BC=E8=87=B4=20AE=20=E8=AF=BB?= =?UTF-8?q?=E5=8F=96=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InfinityBigIntegerCellInventory.java | 34 +++++++++++++++++-- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java index 8642326..d46cf2d 100644 --- a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -240,12 +240,40 @@ public class InfinityBigIntegerCellInventory implements StorageCell { // 获取所有可用的物品堆栈及其数量 @Override public void getAvailableStacks(KeyCounter out) { + // 使用饱和(saturating)加法将 BigInteger 值转换为 long 并安全地累加到 KeyCounter 中。 + // 问题背景:当同一物品存在于多个 cell 中,AE2 的 KeyCounter 使用 long 来记录数量, + // 若简单将单个 cell 的超长值截断为 Long.MAX_VALUE 并直接 add,多个 cell 的合并会导致 + // 原本代表 "大于 long" 的值被重复添加而导致读取异常。解决方案:每次向 KeyCounter 添加前, + // 先读取当前计数器中的已有值(long),并使用 BigInteger 做饱和加法后再写回为 long,避免中间溢出。 + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); Object2ObjectMap map = getCellStoredMap(); for (Object2ObjectMap.Entry entry : map.object2ObjectEntrySet()) { - BigInteger v = entry.getValue(); - long toAdd = v.compareTo(maxLong) > 0 ? Long.MAX_VALUE : v.longValue(); - out.add(entry.getKey(), toAdd); + AEKey key = entry.getKey(); + BigInteger value = entry.getValue(); + + // 当前 KeyCounter 中已有的值(long) + long existing = out.get(key); + + // 将 existing 与当前 value 做 BigInteger 累加并饱和到 Long.MAX_VALUE + BigInteger sum = BigInteger.valueOf(existing).add(value); + long toSet = sum.compareTo(maxLong) > 0 ? Long.MAX_VALUE : sum.longValue(); + + // KeyCounter 没有 set(key,long) 的统一接口暴露(只有 add/remove),所以先移除已存在的值再设置。 + // 为避免读取-写入竞争,我们计算出要新增的 delta 并调用 add(key, delta) + if (existing == Long.MAX_VALUE) { + // 已经饱和,无需再添加 + continue; + } + long delta; + if (toSet == Long.MAX_VALUE) { + delta = Long.MAX_VALUE - existing; + } else { + delta = toSet - existing; + } + if (delta != 0) { + out.add(key, delta); + } } } From 1490f73b5f261aac7b38f00772ff6bc29855a7d8 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 18 Sep 2025 14:32:38 +0800 Subject: [PATCH 38/44] =?UTF-8?q?fix:=20=E4=BF=9D=E8=AF=81=E5=81=9C?= =?UTF-8?q?=E6=AD=A2=E6=97=B6=E5=BC=BA=E5=88=B6=E6=8C=81=E4=B9=85=E5=8C=96?= =?UTF-8?q?=E6=97=A0=E9=99=90=E5=AD=98=E5=82=A8=E5=85=83=E4=BB=B6=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 4 ++ .../InfinityBigIntegerCellInventory.java | 43 +++++++++++-------- .../extendedae_plus/ae/client/gui/Icon.java | 33 -------------- 3 files changed, 29 insertions(+), 51 deletions(-) delete mode 100644 src/main/java/com/extendedae_plus/ae/client/gui/Icon.java diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 6a84267..25d675e 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -3,6 +3,7 @@ package com.extendedae_plus; import appeng.api.storage.StorageCells; import appeng.menu.locator.MenuLocators; import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler; +import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory; import com.extendedae_plus.client.ClientRegistrar; import com.extendedae_plus.config.ModConfig; import com.extendedae_plus.init.*; @@ -54,6 +55,9 @@ public class ExtendedAEPlus { MinecraftForge.EVENT_BUS.addListener(ExtendedAEPlus::onLevelLoad); // 注册通用配置 ModConfig.init(); + // 注册 InfinityBigIntegerCellInventory 的事件监听(tick flush 与停止时 flush) + MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerTick); + MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerStopping); // ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC); } diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java index d46cf2d..2cbb417 100644 --- a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -17,8 +17,8 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; import net.minecraft.world.item.ItemStack; -import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.event.TickEvent; +import net.minecraftforge.event.server.ServerStoppingEvent; import java.math.BigDecimal; import java.math.BigInteger; @@ -27,6 +27,7 @@ import java.text.DecimalFormat; import java.util.UUID; import java.util.concurrent.ConcurrentLinkedQueue; +import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; /** * InfinityBigIntegerCellInventory *

@@ -50,15 +51,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { // 数字格式化对象,保留两位小数(复用以减少对象分配) private static final DecimalFormat DF = new DecimalFormat("#.##"); - static { - // 在类加载时注册服务器 tick 监听器,用于在主线程合并写入 - try { - MinecraftForge.EVENT_BUS.addListener(InfinityBigIntegerCellInventory::onServerTick); - } catch (Throwable ignored) { - // 保守降级:若注册失败,不阻塞实例化 - } - } - // 关联的 ItemStack(含可能的 uuid NBT) private final ItemStack stack; // AE2 提供的保存提供者,用于在容器中批量保存时触发回调 @@ -97,7 +89,7 @@ public class InfinityBigIntegerCellInventory implements StorageCell { } // 服务器 tick 回调:合并并执行待持久化项 - private static void onServerTick(TickEvent.ServerTickEvent event) { + public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase != TickEvent.Phase.END) return; InfinityBigIntegerCellInventory inv; // 处理本次 tick 中的全部待持久化项 @@ -107,11 +99,32 @@ public class InfinityBigIntegerCellInventory implements StorageCell { inv.persist(); } } catch (Throwable ignored) { - // 忽略单项错误,继续处理其余队列 + LOGGER.info("InfinityBigIntegerCellInventory onServerTick error: {}", ignored.getMessage()); } } } + // 在服务器停止时被调用,立即强制持久化队列中的所有实例 + public static void onServerStopping(ServerStoppingEvent event) { + InfinityBigIntegerCellInventory inv; + while ((inv = PENDING_PERSIST.poll()) != null) { + try { + if (!inv.isPersisted) { + inv.persist(); + } + } catch (Throwable ignored) { + LOGGER.info("InfinityBigIntegerCellInventory onServerStopping error1: {}", ignored.getMessage()); + } + } + // 额外尝试将全局存储管理器标记为脏以确保 SavedData 被写回(在单人模式下可能直接由系统触发) + try { + var stor = getStorageInstance(); + if (stor != null) stor.setDirty(); + } catch (Throwable ignored) { + LOGGER.info("InfinityBigIntegerCellInventory onServerStopping error2: {}", ignored.getMessage()); + } + } + // 将 BigInteger 格式化为带单位的字符串,保留两位小数 public static String formatBigInteger(BigInteger number) { // 使用局部 DF(非线程安全),但 Minecraft 通常在主线程运行 @@ -240,12 +253,6 @@ public class InfinityBigIntegerCellInventory implements StorageCell { // 获取所有可用的物品堆栈及其数量 @Override public void getAvailableStacks(KeyCounter out) { - // 使用饱和(saturating)加法将 BigInteger 值转换为 long 并安全地累加到 KeyCounter 中。 - // 问题背景:当同一物品存在于多个 cell 中,AE2 的 KeyCounter 使用 long 来记录数量, - // 若简单将单个 cell 的超长值截断为 Long.MAX_VALUE 并直接 add,多个 cell 的合并会导致 - // 原本代表 "大于 long" 的值被重复添加而导致读取异常。解决方案:每次向 KeyCounter 添加前, - // 先读取当前计数器中的已有值(long),并使用 BigInteger 做饱和加法后再写回为 long,避免中间溢出。 - BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); Object2ObjectMap map = getCellStoredMap(); for (Object2ObjectMap.Entry entry : map.object2ObjectEntrySet()) { diff --git a/src/main/java/com/extendedae_plus/ae/client/gui/Icon.java b/src/main/java/com/extendedae_plus/ae/client/gui/Icon.java deleted file mode 100644 index 9574df3..0000000 --- a/src/main/java/com/extendedae_plus/ae/client/gui/Icon.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.extendedae_plus.ae.client.gui; - -import appeng.client.gui.style.Blitter; -import com.extendedae_plus.ExtendedAEPlus; -import net.minecraft.resources.ResourceLocation; - -public enum Icon { - REDSTONE_LOW(0, 0), - REDSTONE_HIGH(16, 0); - - public final int x; - public final int y; - public final int width; - public final int height; - public static final ResourceLocation TEXTURE = new ResourceLocation(ExtendedAEPlus.MODID, "textures/guis/states.png"); - public static final int TEXTURE_WIDTH = 256; - public static final int TEXTURE_HEIGHT = 256; - - private Icon(int x, int y) { - this(x, y, 16, 16); - } - - private Icon(int x, int y, int width, int height) { - this.x = x; - this.y = y; - this.width = width; - this.height = height; - } - - public Blitter getBlitter() { - return Blitter.texture(TEXTURE, TEXTURE_WIDTH, TEXTURE_HEIGHT).src(this.x, this.y, this.width, this.height); - } -} From b3e129e03c942ed24daca07b79a1ee7c6ad19ac9 Mon Sep 17 00:00:00 2001 From: GaLicn <133291877+GaLicn@users.noreply.github.com> Date: Thu, 18 Sep 2025 16:18:57 +0800 Subject: [PATCH 39/44] =?UTF-8?q?ME=E6=8E=A5=E5=8F=A3=E4=B8=AD=E6=8C=89?= =?UTF-8?q?=E9=92=AE=E5=AE=9E=E7=8E=B0=E7=82=B9=E5=87=BB=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/init/ModNetwork.java | 6 + .../AbstractContainerScreenAccessor.java | 2 + .../ae2/client/gui/InterfaceScreenMixin.java | 137 +++++++++++++++++- .../InterfaceAdjustConfigAmountC2SPacket.java | 116 +++++++++++++++ 4 files changed, 255 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java diff --git a/src/main/java/com/extendedae_plus/init/ModNetwork.java b/src/main/java/com/extendedae_plus/init/ModNetwork.java index 2f4eab5..e281d81 100644 --- a/src/main/java/com/extendedae_plus/init/ModNetwork.java +++ b/src/main/java/com/extendedae_plus/init/ModNetwork.java @@ -97,6 +97,12 @@ public class ModNetwork { .consumerNetworkThread(ToggleEntityTickerC2SPacket::handle) .add(); + CHANNEL.messageBuilder(InterfaceAdjustConfigAmountC2SPacket.class, nextId(), NetworkDirection.PLAY_TO_SERVER) + .encoder(InterfaceAdjustConfigAmountC2SPacket::encode) + .decoder(InterfaceAdjustConfigAmountC2SPacket::decode) + .consumerNetworkThread(InterfaceAdjustConfigAmountC2SPacket::handle) + .add(); + CHANNEL.messageBuilder(AdvancedBlockingSyncS2CPacket.class, nextId(), NetworkDirection.PLAY_TO_CLIENT) .encoder(AdvancedBlockingSyncS2CPacket::encode) .decoder(AdvancedBlockingSyncS2CPacket::decode) diff --git a/src/main/java/com/extendedae_plus/mixin/accessor/AbstractContainerScreenAccessor.java b/src/main/java/com/extendedae_plus/mixin/accessor/AbstractContainerScreenAccessor.java index 27b50a0..ea1eef0 100644 --- a/src/main/java/com/extendedae_plus/mixin/accessor/AbstractContainerScreenAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/accessor/AbstractContainerScreenAccessor.java @@ -2,6 +2,7 @@ package com.extendedae_plus.mixin.accessor; import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen; import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.Slot; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; @@ -11,4 +12,5 @@ public interface AbstractContainerScreenAccessor { @Unique private int eap$lastTopPos = -1; @Unique private int eap$lastImageWidth = -1; @Unique private int eap$lastImageHeight = -1; + // 记录最近一次在 CONFIG 槽位区域内悬停到的配置槽索引, + // 以便当鼠标移到按钮上导致 hoveredSlot 为空时仍能进行操作。 + @Unique private int eap$lastConfigIndex = -1; @Inject(method = "init", at = @At("TAIL")) private void eap$addScaleButtons(CallbackInfo ci) { @@ -45,42 +52,42 @@ public abstract class InterfaceScreenMixin { // 避免重复创建 if (eap$x2Button == null) { eap$x2Button = new ActionEPPButton((b) -> { - // 点击逻辑留空 + eap$sendAdjustForAllConfigs(false, 2); }, NewIcon.MULTIPLY2); eap$x2Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply2"))); eap$x2Button.setVisibility(true); } if (eap$divideBy2Button == null) { eap$divideBy2Button = new ActionEPPButton((b) -> { - // 点击逻辑留空 + eap$sendAdjustForAllConfigs(true, 2); }, NewIcon.DIVIDE2); eap$divideBy2Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide2"))); eap$divideBy2Button.setVisibility(true); } if (eap$x5Button == null) { eap$x5Button = new ActionEPPButton((b) -> { - // 点击逻辑留空 + eap$sendAdjustForAllConfigs(false, 5); }, NewIcon.MULTIPLY5); eap$x5Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply5"))); eap$x5Button.setVisibility(true); } if (eap$divideBy5Button == null) { eap$divideBy5Button = new ActionEPPButton((b) -> { - // 点击逻辑留空 + eap$sendAdjustForAllConfigs(true, 5); }, NewIcon.DIVIDE5); eap$divideBy5Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide5"))); eap$divideBy5Button.setVisibility(true); } if (eap$x10Button == null) { eap$x10Button = new ActionEPPButton((b) -> { - // 点击逻辑留空 + eap$sendAdjustForAllConfigs(false, 10); }, NewIcon.MULTIPLY10); eap$x10Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply10"))); eap$x10Button.setVisibility(true); } if (eap$divideBy10Button == null) { eap$divideBy10Button = new ActionEPPButton((b) -> { - // 点击逻辑留空 + eap$sendAdjustForAllConfigs(true, 10); }, NewIcon.DIVIDE10); eap$divideBy10Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide10"))); eap$divideBy10Button.setVisibility(true); @@ -156,6 +163,78 @@ public abstract class InterfaceScreenMixin { eap$relayoutButtons(); try { LogUtils.getLogger().info("[EAP][InterfaceMixin] relayout due to bounds change: left={}, top={}, w={}, h={}", curLeft, curTop, curImgW, curImgH); } catch (Throwable ignored) {} } + // 每帧根据 hoveredSlot 刷新最近一次的配置槽索引 + eap$updateLastConfigFromHover(); + } + + @Unique + private void eap$sendAdjustForHoveredConfig(boolean divide, int factor) { + try { + // 仅在 InterfaceScreen 中生效 + if (!(((Object) this) instanceof InterfaceScreen)) { + return; + } + // 获取悬停槽位 + Slot hovered = ((AbstractContainerScreenAccessor) (Object) this).eap$getHoveredSlot(); + // 获取菜单与配置槽列表 + var screen = (AEBaseScreen) (Object) this; + var menu = screen.getMenu(); + if (!(menu instanceof appeng.menu.implementations.InterfaceMenu interfaceMenu)) { + return; + } + var configSlots = interfaceMenu.getSlots(SlotSemantics.CONFIG); + if (configSlots == null || configSlots.isEmpty()) { + return; + } + + // 优先根据 hoveredSlot 解析索引;若 hovered 为空,则回退使用最近一次的配置槽索引 + Integer slotFieldObj = null; + if (hovered != null) { + for (var s : configSlots) { + if (s == hovered) { + // 反射读取 AppEngSlot#slot + try { + var f = s.getClass().getDeclaredField("slot"); + f.setAccessible(true); + Object v = f.get(s); + if (v instanceof Integer i) { + slotFieldObj = i; + } + } catch (Throwable ignored) {} + if (slotFieldObj == null) { + // 回退:使用列表位置当作索引 + slotFieldObj = configSlots.indexOf(s); + } + break; + } + } + } + int slotField = -1; + if (slotFieldObj != null) { + slotField = slotFieldObj; + } else if (eap$lastConfigIndex >= 0 && eap$lastConfigIndex < configSlots.size()) { + slotField = eap$lastConfigIndex; + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] Using last hovered config index: {}", slotField); } catch (Throwable ignored) {} + } + if (slotField < 0) { + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] No hovered slot and no last config index; ignoring adjust."); } catch (Throwable ignored) {} + return; + } + + // 发送到服务端 + ModNetwork.CHANNEL.sendToServer(new InterfaceAdjustConfigAmountC2SPacket(slotField, divide, factor)); + } catch (Throwable ignored) {} + } + + @Unique + private void eap$sendAdjustForAllConfigs(boolean divide, int factor) { + try { + if (!(((Object) this) instanceof InterfaceScreen)) { + return; + } + // 直接发送 -1 表示对所有 CONFIG 槽生效 + ModNetwork.CHANNEL.sendToServer(new InterfaceAdjustConfigAmountC2SPacket(-1, divide, factor)); + } catch (Throwable ignored) {} } @Unique @@ -176,4 +255,50 @@ public abstract class InterfaceScreenMixin { if (eap$x10Button != null) { eap$x10Button.setX(bx); eap$x10Button.setY(by + spacing * 5); } } catch (Throwable ignored) {} } + + @Unique + private void eap$updateLastConfigFromHover() { + try { + if (!(((Object) this) instanceof InterfaceScreen)) { + return; + } + Slot hovered = ((AbstractContainerScreenAccessor) (Object) this).eap$getHoveredSlot(); + if (hovered == null) { + return; + } + var screen = (AEBaseScreen) (Object) this; + var menu = screen.getMenu(); + if (!(menu instanceof appeng.menu.implementations.InterfaceMenu interfaceMenu)) { + return; + } + var configSlots = interfaceMenu.getSlots(SlotSemantics.CONFIG); + if (configSlots == null || configSlots.isEmpty()) { + return; + } + // 在 CONFIG 槽列表中定位 hovered 对应的索引 + Integer idx = null; + for (var s : configSlots) { + if (s == hovered) { + try { + var f = s.getClass().getDeclaredField("slot"); + f.setAccessible(true); + Object v = f.get(s); + if (v instanceof Integer i) { + idx = i; + } + } catch (Throwable ignored) {} + if (idx == null) { + idx = configSlots.indexOf(s); + } + break; + } + } + if (idx != null && idx >= 0) { + if (eap$lastConfigIndex != idx) { + eap$lastConfigIndex = idx; + try { LogUtils.getLogger().info("[EAP][InterfaceMixin] lastConfigIndex updated: {}", eap$lastConfigIndex); } catch (Throwable ignored) {} + } + } + } catch (Throwable ignored) {} + } } diff --git a/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java b/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java new file mode 100644 index 0000000..8afc583 --- /dev/null +++ b/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java @@ -0,0 +1,116 @@ +package com.extendedae_plus.network; + +import appeng.menu.implementations.InterfaceMenu; +import appeng.menu.SlotSemantics; +import appeng.api.stacks.GenericStack; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.server.level.ServerPlayer; +import net.minecraftforge.network.NetworkEvent; + +import java.util.function.Supplier; + +/** + * C2S:调整 ME 接口配置槽位(标记物品)的数量。 + * 支持按因子倍增或整除,且保持最小值为 1。 + */ +public class InterfaceAdjustConfigAmountC2SPacket { + private final int slotIndex; // 配置槽位索引(ConfigInventory 索引) + private final boolean divide; // true 表示做除法,否则做乘法 + private final int factor; // 因子:2/5/10 + + public InterfaceAdjustConfigAmountC2SPacket(int slotIndex, boolean divide, int factor) { + this.slotIndex = slotIndex; + this.divide = divide; + this.factor = factor; + } + + public static void encode(InterfaceAdjustConfigAmountC2SPacket msg, FriendlyByteBuf buf) { + buf.writeVarInt(msg.slotIndex); + buf.writeBoolean(msg.divide); + buf.writeVarInt(msg.factor); + } + + public static InterfaceAdjustConfigAmountC2SPacket decode(FriendlyByteBuf buf) { + int slot = buf.readVarInt(); + boolean div = buf.readBoolean(); + int factor = buf.readVarInt(); + return new InterfaceAdjustConfigAmountC2SPacket(slot, div, factor); + + } + + public static void handle(InterfaceAdjustConfigAmountC2SPacket msg, Supplier ctxSupplier) { + var ctx = ctxSupplier.get(); + ctx.enqueueWork(() -> { + ServerPlayer player = ctx.getSender(); + if (player == null) return; + if (!(player.containerMenu instanceof InterfaceMenu menu)) return; + + try { + var logic = menu.getHost().getInterfaceLogic(); + var config = logic.getConfig(); + if (msg.slotIndex == -1) { + // 对所有 CONFIG 槽位生效 + var configSlots = menu.getSlots(SlotSemantics.CONFIG); + if (configSlots == null || configSlots.isEmpty()) return; + for (var s : configSlots) { + int idx = -1; + try { + var f = s.getClass().getDeclaredField("slot"); + f.setAccessible(true); + Object v = f.get(s); + if (v instanceof Integer i) idx = i; + } catch (Throwable ignored) {} + if (idx < 0) { + idx = configSlots.indexOf(s); + } + + var st = config.getStack(idx); + if (st == null) continue; + + long current = st.amount(); + int factor = Math.max(1, msg.factor); + long next; + if (msg.divide) { + if (factor <= 1) continue; + if (current % factor != 0) continue; + next = current / factor; + if (next < 1) next = 1; + } else { + if (factor <= 1) continue; + next = current * factor; + if (next < 1) next = 1; + } + + GenericStack newStack = new GenericStack(st.what(), next); + config.setStack(idx, newStack); + } + } else { + var stack = config.getStack(msg.slotIndex); + if (stack == null) return; // 槽位无标记 + + long current = stack.amount(); + int factor = Math.max(1, msg.factor); + long next; + if (msg.divide) { + // 只能整除,且至少为 1 + if (factor <= 1) return; + if (current % factor != 0) return; // 不能整除则跳过 + next = current / factor; + if (next < 1) next = 1; + } else { + // 倍增,至少为 1 + if (factor <= 1) return; + next = current * factor; + if (next < 1) next = 1; + } + + // 应用 + GenericStack newStack = new GenericStack(stack.what(), next); + config.setStack(msg.slotIndex, newStack); + } + // 不需要显式保存:InterfaceLogic.config 的变更监听器会触发 host.saveChanges() 与计划更新 + } catch (Throwable ignored) {} + }); + ctx.setPacketHandled(true); + } +} From 23dcd69a3902ecc7442dde5d38aee24567637e56 Mon Sep 17 00:00:00 2001 From: GaLicn <133291877+GaLicn@users.noreply.github.com> Date: Thu, 18 Sep 2025 16:26:20 +0800 Subject: [PATCH 40/44] =?UTF-8?q?=E5=90=8C=E6=AD=A5ME=E6=89=A9=E5=B1=95?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae2/client/gui/InterfaceScreenMixin.java | 26 +++++++++++++--- .../InterfaceAdjustConfigAmountC2SPacket.java | 31 +++++++++---------- 2 files changed, 35 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java index 06906b5..72757a1 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java @@ -44,8 +44,8 @@ public abstract class InterfaceScreenMixin { @Inject(method = "init", at = @At("TAIL")) private void eap$addScaleButtons(CallbackInfo ci) { - // 仅在 InterfaceScreen 实例中添加 - if (!(((Object) this) instanceof InterfaceScreen)) { + // 仅在 AE2 接口界面或 ExtendedAE 扩展接口界面中添加 + if (!eap$isSupportedInterfaceScreen()) { return; } try { LogUtils.getLogger().info("[EAP][InterfaceMixin] init tail reached, preparing scale buttons."); } catch (Throwable ignored) {} @@ -115,7 +115,7 @@ public abstract class InterfaceScreenMixin { @Inject(method = "containerTick", at = @At("TAIL")) private void eap$ensureButtons(CallbackInfo ci) { - if (!(((Object) this) instanceof InterfaceScreen)) { + if (!eap$isSupportedInterfaceScreen()) { return; } var accessor = (ScreenAccessor) (Object) this; @@ -171,7 +171,7 @@ public abstract class InterfaceScreenMixin { private void eap$sendAdjustForHoveredConfig(boolean divide, int factor) { try { // 仅在 InterfaceScreen 中生效 - if (!(((Object) this) instanceof InterfaceScreen)) { + if (!eap$isSupportedInterfaceScreen()) { return; } // 获取悬停槽位 @@ -229,7 +229,7 @@ public abstract class InterfaceScreenMixin { @Unique private void eap$sendAdjustForAllConfigs(boolean divide, int factor) { try { - if (!(((Object) this) instanceof InterfaceScreen)) { + if (!eap$isSupportedInterfaceScreen()) { return; } // 直接发送 -1 表示对所有 CONFIG 槽生效 @@ -237,6 +237,22 @@ public abstract class InterfaceScreenMixin { } catch (Throwable ignored) {} } + @Unique + private boolean eap$isSupportedInterfaceScreen() { + // AE2 原版接口界面 + if (((Object) this) instanceof InterfaceScreen) { + return true; + } + // ExtendedAE 扩展接口界面(使用类名判断避免编译期硬依赖) + try { + String cn = ((Object) this).getClass().getName(); + if ("com.glodblock.github.extendedae.client.gui.GuiExInterface".equals(cn)) { + return true; + } + } catch (Throwable ignored) {} + return false; + } + @Unique private void eap$relayoutButtons() { try { diff --git a/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java b/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java index 8afc583..8d899ed 100644 --- a/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java +++ b/src/main/java/com/extendedae_plus/network/InterfaceAdjustConfigAmountC2SPacket.java @@ -43,27 +43,24 @@ public class InterfaceAdjustConfigAmountC2SPacket { ctx.enqueueWork(() -> { ServerPlayer player = ctx.getSender(); if (player == null) return; - if (!(player.containerMenu instanceof InterfaceMenu menu)) return; + // 支持 AE2 原版接口和 ExtendedAE 扩展接口 + InterfaceMenu menu = null; + com.glodblock.github.extendedae.container.ContainerExInterface exMenu = null; + if (player.containerMenu instanceof InterfaceMenu im) { + menu = im; + } else if (player.containerMenu instanceof com.glodblock.github.extendedae.container.ContainerExInterface cem) { + exMenu = cem; + } else { + return; + } try { - var logic = menu.getHost().getInterfaceLogic(); + var logic = (menu != null ? menu.getHost() : exMenu.getHost()).getInterfaceLogic(); var config = logic.getConfig(); if (msg.slotIndex == -1) { - // 对所有 CONFIG 槽位生效 - var configSlots = menu.getSlots(SlotSemantics.CONFIG); - if (configSlots == null || configSlots.isEmpty()) return; - for (var s : configSlots) { - int idx = -1; - try { - var f = s.getClass().getDeclaredField("slot"); - f.setAccessible(true); - Object v = f.get(s); - if (v instanceof Integer i) idx = i; - } catch (Throwable ignored) {} - if (idx < 0) { - idx = configSlots.indexOf(s); - } - + // 对所有配置槽统一生效(不依赖槽位语义,直接按 config.size() 遍历) + int size = config.size(); + for (int idx = 0; idx < size; idx++) { var st = config.getStack(idx); if (st == null) continue; From d78f8a645fdb0be228c99c31100d5351c16dae97 Mon Sep 17 00:00:00 2001 From: GaLicn <133291877+GaLicn@users.noreply.github.com> Date: Thu, 18 Sep 2025 16:36:04 +0800 Subject: [PATCH 41/44] 1.4.2 --- CHANGELOG.md | 6 ++++-- gradle.properties | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a056e01..0176c3e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,8 @@ # Changelog -## [Unreleased] / [未发布] +## [Unreleased] -## [1.4.2] / [未发布] +## [1.4.2] ### Added / 新增 - 添加实体加速器,最高可加速 1024 倍(配置文件可配置能耗、黑名单、额外消耗倍率名单) - Added Entity Accelerator block, capable of up to 1024× acceleration (configurable energy cost, blacklist, and extra consumption multiplier list). @@ -26,6 +26,8 @@ - Adjusted display limit for pattern output quantity. - 放宽扩展供应器样板手动倍增限制 - Relaxed manual doubling restrictions for Extended Providers. +- 为ME接口添加倍增按钮用于倍增标记物品数量 + - Add a multiplier button to the ME interface for multiplying the marked item quantity ### Fixed / 修复 - 修复无线收发器频道限制与渲染问题 - Fixed channel limit and rendering issues for Wireless Repeater. diff --git a/gradle.properties b/gradle.properties index d7ffbbb..21dcae0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.4.2-beta +mod_version = 1.4.2 maven_group = com.extendedae_plus archives_name = extendedae_plus From 5ca15ac506fa558be47305a131736c0d1ca9fb2a Mon Sep 17 00:00:00 2001 From: GaLicn <133291877+GaLicn@users.noreply.github.com> Date: Thu, 18 Sep 2025 17:05:01 +0800 Subject: [PATCH 42/44] 1.4.2 --- .../mixin/ae2/client/gui/InterfaceScreenMixin.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java index 72757a1..0c6f828 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/InterfaceScreenMixin.java @@ -54,42 +54,42 @@ public abstract class InterfaceScreenMixin { eap$x2Button = new ActionEPPButton((b) -> { eap$sendAdjustForAllConfigs(false, 2); }, NewIcon.MULTIPLY2); - eap$x2Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply2"))); + eap$x2Button.setTooltip(null); eap$x2Button.setVisibility(true); } if (eap$divideBy2Button == null) { eap$divideBy2Button = new ActionEPPButton((b) -> { eap$sendAdjustForAllConfigs(true, 2); }, NewIcon.DIVIDE2); - eap$divideBy2Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide2"))); + eap$divideBy2Button.setTooltip(null); eap$divideBy2Button.setVisibility(true); } if (eap$x5Button == null) { eap$x5Button = new ActionEPPButton((b) -> { eap$sendAdjustForAllConfigs(false, 5); }, NewIcon.MULTIPLY5); - eap$x5Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply5"))); + eap$x5Button.setTooltip(null); eap$x5Button.setVisibility(true); } if (eap$divideBy5Button == null) { eap$divideBy5Button = new ActionEPPButton((b) -> { eap$sendAdjustForAllConfigs(true, 5); }, NewIcon.DIVIDE5); - eap$divideBy5Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide5"))); + eap$divideBy5Button.setTooltip(null); eap$divideBy5Button.setVisibility(true); } if (eap$x10Button == null) { eap$x10Button = new ActionEPPButton((b) -> { eap$sendAdjustForAllConfigs(false, 10); }, NewIcon.MULTIPLY10); - eap$x10Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.multiply10"))); + eap$x10Button.setTooltip(null); eap$x10Button.setVisibility(true); } if (eap$divideBy10Button == null) { eap$divideBy10Button = new ActionEPPButton((b) -> { eap$sendAdjustForAllConfigs(true, 10); }, NewIcon.DIVIDE10); - eap$divideBy10Button.setTooltip(Tooltip.create(Component.translatable("extendedae_plus.button.divide10"))); + eap$divideBy10Button.setTooltip(null); eap$divideBy10Button.setVisibility(true); } From 121828d8f1e7b7fa601543837866764fb306cb25 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 19 Sep 2025 03:27:36 +0800 Subject: [PATCH 43/44] =?UTF-8?q?fix:=20=E5=90=88=E6=88=90=E8=AE=A1?= =?UTF-8?q?=E5=88=92=E7=95=8C=E9=9D=A2=E6=B7=BB=E5=8A=A0=E7=BC=BA=E5=B0=91?= =?UTF-8?q?=E7=89=A9=E5=93=81=E9=81=87=E5=88=B0=E6=B5=81=E4=BD=93=EF=BC=8C?= =?UTF-8?q?mek=E5=8C=96=E5=AD=A6=E5=93=81=E4=BC=9A=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E9=94=99=E8=AF=AF=E4=B9=A6=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../integration/jei/JeiRuntimeProxy.java | 103 +++++++++++++++++- .../ae2/menu/CraftConfirmMenuGoBackMixin.java | 25 ++++- .../resources/extendedae_plus.mixins.json | 4 +- 3 files changed, 124 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java b/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java index 3965a63..bc5276e 100644 --- a/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java +++ b/src/main/java/com/extendedae_plus/integration/jei/JeiRuntimeProxy.java @@ -2,6 +2,8 @@ package com.extendedae_plus.integration.jei; import com.extendedae_plus.mixin.jei.accessor.BookmarkOverlayAccessor; import mezz.jei.api.constants.VanillaTypes; +import mezz.jei.api.forge.ForgeTypes; +import mezz.jei.api.ingredients.IIngredientType; import mezz.jei.api.ingredients.ITypedIngredient; import mezz.jei.api.runtime.IBookmarkOverlay; import mezz.jei.api.runtime.IIngredientListOverlay; @@ -10,8 +12,13 @@ import mezz.jei.gui.bookmarks.BookmarkList; import mezz.jei.gui.bookmarks.IngredientBookmark; import mezz.jei.gui.overlay.elements.IElement; import net.minecraft.world.item.ItemStack; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fml.ModList; +import org.spongepowered.asm.mixin.Pseudo; import javax.annotation.Nullable; +import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -19,10 +26,12 @@ import java.util.Optional; /** * 线程安全地缓存并访问 JEI Runtime。 */ +@Pseudo public final class JeiRuntimeProxy { private static volatile IJeiRuntime RUNTIME; - private JeiRuntimeProxy() {} + private JeiRuntimeProxy() { + } static void setRuntime(IJeiRuntime runtime) { RUNTIME = runtime; @@ -135,9 +144,6 @@ public final class JeiRuntimeProxy { return Collections.emptyList(); } - /** - * 将物品添加到 JEI 书签 - */ public static void addBookmark(ItemStack stack) { IJeiRuntime rt = RUNTIME; if (rt == null) return; @@ -154,6 +160,95 @@ public final class JeiRuntimeProxy { } } + public static void addBookmark(FluidStack fluidStack) { + IJeiRuntime rt = RUNTIME; + if (rt == null) return; + + IBookmarkOverlay overlay = rt.getBookmarkOverlay(); + if (overlay instanceof BookmarkOverlayAccessor accessor) { + BookmarkList list = accessor.eap$getBookmarkList(); + Optional> typedOpt = rt.getIngredientManager() + .createTypedIngredient(ForgeTypes.FLUID_STACK, fluidStack); + typedOpt.ifPresent(typed -> { + IngredientBookmark bookmark = IngredientBookmark.create(typed, rt.getIngredientManager()); + list.add(bookmark); // add 内部会自动保存到配置 + }); + } + } + + /** + * 如果存在 Mekanism/appmek,则将 Mekanism 化学堆栈添加到 JEI 书签。 + */ + public static void addBookmark(Object chemicalStack) { + if (!ModList.get().isLoaded("mekanism") && !ModList.get().isLoaded("appmek")) return; + + IJeiRuntime rt = RUNTIME; + if (rt == null) return; + + IBookmarkOverlay overlay = rt.getBookmarkOverlay(); + if (overlay instanceof BookmarkOverlayAccessor accessor) { + BookmarkList list = accessor.eap$getBookmarkList(); + try { + if (chemicalStack == null) return; + + // Determine Mekanism JEI ingredient type constant by runtime class name + String clsName = chemicalStack.getClass().getName(); + String mekanismJeiClass = "mekanism.client.jei.MekanismJEI"; + Class jeiCls = Class.forName(mekanismJeiClass); + Field typeField = getField(clsName, jeiCls); + + if (typeField == null) return; + Object typeConst = typeField.get(null); + + // Use ingredient manager reflectively to create a typed ingredient + Object ingredientManager = rt.getIngredientManager(); + Method createTypedIngredient = ingredientManager.getClass().getMethod("createTypedIngredient", IIngredientType.class, Object.class); + Object opt = createTypedIngredient.invoke(ingredientManager, typeConst, chemicalStack); + if (!(opt instanceof Optional typedOpt)) return; + if (typedOpt.isPresent()) { + Object typed = typedOpt.get(); + // Find a compatible static create(...) method on IngredientBookmark where + // the second parameter is assignable from the actual ingredientManager instance. + Method createMethod = null; + for (Method m : IngredientBookmark.class.getMethods()) { + if (!m.getName().equals("create")) continue; + Class[] params = m.getParameterTypes(); + if (params.length != 2) continue; + // first param should accept the typed ingredient + boolean firstOk = params[0].isAssignableFrom(typed.getClass()) || params[0].isAssignableFrom(ITypedIngredient.class); + boolean secondOk = params[1].isAssignableFrom(ingredientManager.getClass()); + if (firstOk && secondOk) { + createMethod = m; + break; + } + } + if (createMethod != null) { + Object bookmark = createMethod.invoke(null, typed, ingredientManager); + if (bookmark != null) { + list.add((IngredientBookmark) bookmark); + } + } + } + } catch (Throwable e) { + e.printStackTrace(); + } + } + } + + private static @Nullable Field getField(String clsName, Class jeiCls) throws NoSuchFieldException { + Field typeField = null; + if ("mekanism.api.chemical.gas.GasStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_GAS"); + } else if ("mekanism.api.chemical.infuse.InfusionStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_INFUSION"); + } else if ("mekanism.api.chemical.pigment.PigmentStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_PIGMENT"); + } else if ("mekanism.api.chemical.slurry.SlurryStack".equals(clsName)) { + typeField = jeiCls.getField("TYPE_SLURRY"); + } + return typeField; + } + /** * 从 JEI 书签移除物品 */ diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java index 0bbc164..c5e2d23 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/CraftConfirmMenuGoBackMixin.java @@ -1,10 +1,13 @@ package com.extendedae_plus.mixin.ae2.menu; +import appeng.api.stacks.AEFluidKey; +import appeng.api.stacks.AEItemKey; import appeng.menu.me.crafting.CraftConfirmMenu; import appeng.menu.me.crafting.CraftingPlanSummary; import appeng.menu.me.crafting.CraftingPlanSummaryEntry; import com.extendedae_plus.integration.jei.JeiRuntimeProxy; import net.minecraft.client.gui.screens.Screen; +import net.minecraftforge.fml.ModList; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; @@ -44,9 +47,27 @@ public class CraftConfirmMenuGoBackMixin { // 仅在按住 shift 时为缺失的条目添加 JEI 书签 for (CraftingPlanSummaryEntry entry : entries) { if (entry.getMissingAmount() > 0) { - JeiRuntimeProxy.addBookmark(entry.getWhat().wrapForDisplayOrFilter()); + var what = entry.getWhat(); + if (what instanceof AEItemKey aeItemKey) { + JeiRuntimeProxy.addBookmark(aeItemKey.getReadOnlyStack()); + } else if (what instanceof AEFluidKey aeFluidKey) { + JeiRuntimeProxy.addBookmark(aeFluidKey.toStack(1000)); + } else if (ModList.get().isLoaded("appmek") && ModList.get().isLoaded("mekanism")) { + try { + if (what != null) { + // avoid compile-time dependency on MekanismKey by reflection + Class mekanismKeyCls = Class.forName("me.ramidzkh.mekae2.ae2.MekanismKey"); + if (mekanismKeyCls.isInstance(what)) { + java.lang.reflect.Method m = mekanismKeyCls.getMethod("getStack"); + Object stack = m.invoke(what); + JeiRuntimeProxy.addBookmark(stack); + } + } + } catch (Throwable ignored) {} + } } } - } catch (Throwable ignored) {} + } catch (Throwable ignored) { + } } } \ No newline at end of file diff --git a/src/main/resources/extendedae_plus.mixins.json b/src/main/resources/extendedae_plus.mixins.json index a69afbb..aaad6df 100644 --- a/src/main/resources/extendedae_plus.mixins.json +++ b/src/main/resources/extendedae_plus.mixins.json @@ -16,11 +16,12 @@ "ae2.accessor.PatternAccessTermScreenAccessor", "ae2.accessor.PatternAccessTermScreenSlotsRowAccessor", "ae2.client.gui.AEBaseScreenMixin", - "ae2.client.gui.PatternEncodingTermScreenMixin", "ae2.client.gui.InterfaceScreenMixin", + "ae2.client.gui.PatternEncodingTermScreenMixin", "ae2.client.gui.PatternProviderCloseMixin", "ae2.client.gui.PatternProviderScreenMixin", "ae2.client.gui.SlotGridLayoutMixin", + "ae2.menu.CraftConfirmMenuGoBackMixin", "extendedae.accessor.GuiExPatternTerminalAccessor", "extendedae.accessor.GuiExPatternTerminalSlotsRowAccessor", "extendedae.client.HighlightButtonMixin", @@ -57,7 +58,6 @@ "ae2.helpers.PatternProviderLogicAdvancedMixin", "ae2.helpers.PatternProviderLogicDoublingMixin", "ae2.menu.ContainerPatternEncodingTermMenuMixin", - "ae2.menu.CraftConfirmMenuGoBackMixin", "ae2.menu.MEStorageMenuMixin", "ae2.menu.PatternEncodingTermMenuMixin", "ae2.menu.PatternProviderMenuAdvancedMixin", From 49b0ef072613169ed06fc705d6a8f9a82cc5bb98 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 19 Sep 2025 08:22:35 +0800 Subject: [PATCH 44/44] =?UTF-8?q?fix:=20=E5=8F=96=E6=B6=88mixin=E9=83=A8?= =?UTF-8?q?=E5=88=86=E9=9D=9E=E6=B7=B7=E6=B7=86=E5=AD=97=E6=AE=B5=E7=9A=84?= =?UTF-8?q?=E6=B7=B7=E6=B7=86=E6=98=A0=E5=B0=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../AdvPatternProviderMenuAdvancedAccessor.java | 2 +- .../menu/AdvPatternProviderMenuAdvancedMixin.java | 8 +++++--- .../menu/AdvPatternProviderMenuDoublingMixin.java | 8 +++++--- .../mixin/ae2/accessor/MEStorageMenuAccessor.java | 10 +++++----- .../ae2/accessor/PatternEncodingTermMenuAccessor.java | 4 ++-- .../ae2/accessor/PatternProviderLogicAccessor.java | 4 ++-- .../PatternProviderLogicPatternInputsAccessor.java | 2 +- .../accessor/PatternProviderMenuAdvancedAccessor.java | 2 +- .../ae2/autopattern/CraftingTreeNodeAccessor.java | 2 +- .../ae2/autopattern/CraftingTreeProcessMixin.java | 3 ++- .../mixin/ae2/client/gui/AEBaseScreenMixin.java | 2 +- .../mixin/ae2/menu/PatternEncodingTermMenuMixin.java | 8 +++++--- .../ae2/menu/PatternProviderMenuAdvancedMixin.java | 8 +++++--- .../ae2/menu/PatternProviderMenuDoublingMixin.java | 8 +++++--- .../ContainerWirelessExPatternTerminalMixin.java | 2 +- .../mixin/jei/accessor/BookmarkOverlayAccessor.java | 2 +- 17 files changed, 44 insertions(+), 33 deletions(-) diff --git a/gradle.properties b/gradle.properties index 21dcae0..32815b9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,7 +3,7 @@ org.gradle.jvmargs=-Xmx1G loom.platform = forge # Mod properties -mod_version = 1.4.2 +mod_version = 1.4.2-fix maven_group = com.extendedae_plus archives_name = extendedae_plus diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java b/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java index bf6987e..bd75482 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/accessor/AdvPatternProviderMenuAdvancedAccessor.java @@ -7,6 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(AdvPatternProviderMenu.class) public interface AdvPatternProviderMenuAdvancedAccessor { - @Accessor("logic") + @Accessor(value = "logic", remap = false) AdvPatternProviderLogic eap$logic(); } diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java index db4ae90..7cde360 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuAdvancedMixin.java @@ -9,6 +9,7 @@ import net.minecraft.world.inventory.MenuType; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogicHost; import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -18,7 +19,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(AdvPatternProviderMenu.class) public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync { - @Shadow + @Final + @Shadow(remap = false) protected AdvPatternProviderLogic logic; // 选择一个未占用的 GUI 同步 id(AE2 已用到 7),这里使用 21 以避冲突 @@ -38,7 +40,7 @@ public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProv } // 构造器尾注入(public ctor) - @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initAdvancedSync_Public(int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; @@ -49,7 +51,7 @@ public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProv } // 构造器尾注入(protected ctor with MenuType) - @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initAdvancedSync_Protected(MenuType menuType, int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java index 7e63986..8b2e4e9 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/menu/AdvPatternProviderMenuDoublingMixin.java @@ -9,6 +9,7 @@ import net.minecraft.world.inventory.MenuType; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic; import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogicHost; import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -18,7 +19,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @Mixin(AdvPatternProviderMenu.class) public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync { - @Shadow + @Final + @Shadow(remap = false) protected AdvPatternProviderLogic logic; @Unique @@ -35,7 +37,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProv } } - @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initSmartSync_Public(int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; @@ -45,7 +47,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProv } catch (Throwable ignored) {} } - @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lnet/pedroksl/advanced_ae/common/logic/AdvPatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initSmartSync_Protected(MenuType menuType, int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/MEStorageMenuAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/MEStorageMenuAccessor.java index a3662ac..52ce7fe 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/MEStorageMenuAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/MEStorageMenuAccessor.java @@ -10,23 +10,23 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(MEStorageMenu.class) public interface MEStorageMenuAccessor { - @Accessor("storage") + @Accessor(value = "storage", remap = false) @Nullable MEStorage getStorage(); - @Accessor("powerSource") + @Accessor(value = "powerSource", remap = false) @Nullable IEnergySource getPowerSource(); - @Accessor("hasPower") + @Accessor(value = "hasPower", remap = false) boolean getHasPower(); // Access client-side config manager mirror used for syncing settings - @Accessor("clientCM") + @Accessor(value = "clientCM", remap = false) IConfigManager getClientCM(); // Access server-side config manager - @Accessor("serverCM") + @Accessor(value = "serverCM", remap = false) @Nullable IConfigManager getServerCM(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternEncodingTermMenuAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternEncodingTermMenuAccessor.java index 908962c..c87956a 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternEncodingTermMenuAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternEncodingTermMenuAccessor.java @@ -7,9 +7,9 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(PatternEncodingTermMenu.class) public interface PatternEncodingTermMenuAccessor { - @Accessor("encodedPatternSlot") + @Accessor(value = "encodedPatternSlot",remap = false) RestrictedInputSlot eap$getEncodedPatternSlot(); - @Accessor("blankPatternSlot") + @Accessor(value = "blankPatternSlot",remap = false) RestrictedInputSlot eap$getBlankPatternSlot(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java index 1c93b75..6155a13 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicAccessor.java @@ -8,9 +8,9 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(PatternProviderLogic.class) public interface PatternProviderLogicAccessor { - @Accessor("host") + @Accessor(value = "host", remap = false) PatternProviderLogicHost eap$host(); - @Accessor("mainNode") + @Accessor(value = "mainNode", remap = false) IManagedGridNode eap$mainNode(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicPatternInputsAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicPatternInputsAccessor.java index 2b898b5..3f62fd4 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicPatternInputsAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderLogicPatternInputsAccessor.java @@ -9,6 +9,6 @@ import java.util.Set; @Mixin(PatternProviderLogic.class) public interface PatternProviderLogicPatternInputsAccessor { - @Accessor("patternInputs") + @Accessor(value = "patternInputs",remap = false) Set eap$patternInputs(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java index 0a0234d..18ca7b7 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/accessor/PatternProviderMenuAdvancedAccessor.java @@ -7,6 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(PatternProviderMenu.class) public interface PatternProviderMenuAdvancedAccessor { - @Accessor("logic") + @Accessor(value = "logic", remap = false) PatternProviderLogic eap$logic(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeNodeAccessor.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeNodeAccessor.java index 3f4794a..6d5b7b8 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeNodeAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeNodeAccessor.java @@ -7,6 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(CraftingTreeNode.class) public interface CraftingTreeNodeAccessor { - @Accessor("what") + @Accessor(value = "what", remap = false) AEKey eap$getWhat(); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java index d6ce278..8f96a90 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/autopattern/CraftingTreeProcessMixin.java @@ -33,7 +33,8 @@ public abstract class CraftingTreeProcessMixin { @ModifyVariable( method = "(Lappeng/api/networking/crafting/ICraftingService;Lappeng/crafting/CraftingCalculation;Lappeng/api/crafting/IPatternDetails;Lappeng/crafting/CraftingTreeNode;)V", at = @At("HEAD"), - argsOnly = true + argsOnly = true, + remap = false ) private static IPatternDetails eap$replaceDetailsAtHead(IPatternDetails original, ICraftingService cc, CraftingCalculation job, IPatternDetails details, CraftingTreeNode craftingTreeNode) { try { diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java index 5d089eb..5f74500 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/client/gui/AEBaseScreenMixin.java @@ -312,7 +312,7 @@ public abstract class AEBaseScreenMixin { } - @Shadow + @Shadow(remap = false) protected void setTextContent(String id, Component content) {}; @Inject(method = "updateBeforeRender", at = @At("RETURN"), remap = false) diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternEncodingTermMenuMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternEncodingTermMenuMixin.java index a9cc70a..6c76e0b 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternEncodingTermMenuMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternEncodingTermMenuMixin.java @@ -14,6 +14,7 @@ import appeng.menu.slot.RestrictedInputSlot; import com.extendedae_plus.mixin.ae2.accessor.MEStorageMenuAccessor; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.MenuType; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -28,7 +29,8 @@ public abstract class PatternEncodingTermMenuMixin { @Unique private boolean eap$blankAutoFilled = false; - @Shadow + @Final + @Shadow(remap = false) private RestrictedInputSlot blankPatternSlot; @Unique @@ -87,7 +89,7 @@ public abstract class PatternEncodingTermMenuMixin { } @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/IPatternTerminalMenuHost;Z)V", - at = @At("TAIL")) + at = @At("TAIL"), remap = false) private void eap$autoFillBlankPattern(MenuType menuType, int id, Inventory ip, IPatternTerminalMenuHost host, boolean bindInventory, CallbackInfo ci) { @@ -95,7 +97,7 @@ public abstract class PatternEncodingTermMenuMixin { } @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/IPatternTerminalMenuHost;)V", - at = @At("TAIL")) + at = @At("TAIL"), remap = false) private void eap$autoFillCtor3(int id, Inventory ip, IPatternTerminalMenuHost host, CallbackInfo ci) { eap$tryFill(host, ip); } diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java index 8a1fb05..28174ac 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuAdvancedMixin.java @@ -9,6 +9,7 @@ import com.extendedae_plus.api.AdvancedBlockingHolder; import com.extendedae_plus.api.PatternProviderMenuAdvancedSync; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.MenuType; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -20,7 +21,8 @@ import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; @Mixin(PatternProviderMenu.class) public abstract class PatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync { - @Shadow + @Final + @Shadow(remap = false) protected PatternProviderLogic logic; // 选择一个未占用的 GUI 同步 id(AE2 已用到 7),这里使用 20 以避冲突 @@ -40,7 +42,7 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide } // 构造器尾注入(public ctor) - @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initAdvancedSync_Public(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; @@ -51,7 +53,7 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide } // 构造器尾注入(protected ctor with MenuType) - @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initAdvancedSync_Protected(MenuType menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; diff --git a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java index 822c22f..3403b9d 100644 --- a/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/ae2/menu/PatternProviderMenuDoublingMixin.java @@ -9,6 +9,7 @@ import com.extendedae_plus.api.PatternProviderMenuDoublingSync; import com.extendedae_plus.api.SmartDoublingHolder; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.MenuType; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -20,7 +21,8 @@ import static com.extendedae_plus.util.ExtendedAELogger.LOGGER; @Mixin(PatternProviderMenu.class) public abstract class PatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync { - @Shadow + @Final + @Shadow(remap = false) protected PatternProviderLogic logic; @Unique @@ -37,7 +39,7 @@ public abstract class PatternProviderMenuDoublingMixin implements PatternProvide } } - @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initSmartSync_Public(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; @@ -49,7 +51,7 @@ public abstract class PatternProviderMenuDoublingMixin implements PatternProvide } } - @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL")) + @Inject(method = "(Lnet/minecraft/world/inventory/MenuType;ILnet/minecraft/world/entity/player/Inventory;Lappeng/helpers/patternprovider/PatternProviderLogicHost;)V", at = @At("TAIL"), remap = false) private void eap$initSmartSync_Protected(MenuType menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) { try { var l = this.logic; diff --git a/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerWirelessExPatternTerminalMixin.java b/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerWirelessExPatternTerminalMixin.java index 4355a40..ce7a1ab 100644 --- a/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerWirelessExPatternTerminalMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/extendedae/container/ContainerWirelessExPatternTerminalMixin.java @@ -32,7 +32,7 @@ public abstract class ContainerWirelessExPatternTerminalMixin implements IAction private Player epp$player; // 明确目标构造签名:(int, Inventory, HostWirelessExPAT) - @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lcom/glodblock/github/extendedae/common/me/itemhost/HostWirelessExPAT;)V", at = @At("TAIL"), require = 0) + @Inject(method = "(ILnet/minecraft/world/entity/player/Inventory;Lcom/glodblock/github/extendedae/common/me/itemhost/HostWirelessExPAT;)V", at = @At("TAIL"), require = 0, remap = false) private void init(int id, net.minecraft.world.entity.player.Inventory playerInventory, HostWirelessExPAT host, CallbackInfo ci) { this.epp$player = playerInventory.player; // 注册上传动作:参数顺序必须与客户端 CGenericPacket 保持一致 diff --git a/src/main/java/com/extendedae_plus/mixin/jei/accessor/BookmarkOverlayAccessor.java b/src/main/java/com/extendedae_plus/mixin/jei/accessor/BookmarkOverlayAccessor.java index 508845d..0a526ec 100644 --- a/src/main/java/com/extendedae_plus/mixin/jei/accessor/BookmarkOverlayAccessor.java +++ b/src/main/java/com/extendedae_plus/mixin/jei/accessor/BookmarkOverlayAccessor.java @@ -7,6 +7,6 @@ import org.spongepowered.asm.mixin.gen.Accessor; @Mixin(BookmarkOverlay.class) public interface BookmarkOverlayAccessor { - @Accessor("bookmarkList") + @Accessor(value = "bookmarkList", remap = false) BookmarkList eap$getBookmarkList(); }