Merge remote-tracking branch 'origin/develop/fix'

# Conflicts:
#	src/main/java/com/extendedae_plus/compat/UpgradeSlotCompat.java
This commit is contained in:
GaLicn 2025-09-29 19:03:17 +08:00
commit da917d49e3
104 changed files with 1315 additions and 1140 deletions

View File

@ -71,6 +71,7 @@ dependencies {
modImplementation "curse.maven:glodium-957920:${glodium_version}"
//extendedAE
modImplementation files('libs/ExtendedAE-1.20-1.4.2-forge.jar')
modRuntimeOnly fileTree(dir: 'libs', includes: ['*.jar'])
//ae2
modImplementation "appeng:appliedenergistics2-forge:${ae2_version}"

View File

@ -4,10 +4,10 @@ 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.command.InfinityDiskGiveCommand;
import com.extendedae_plus.config.ModConfig;
import com.extendedae_plus.init.*;
import com.extendedae_plus.menu.locator.CuriosItemLocator;
import com.extendedae_plus.util.command.InfinityDiskGiveCommand;
import com.extendedae_plus.util.storage.InfinityStorageManager;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist;

View File

@ -0,0 +1,41 @@
package com.extendedae_plus.ae.api.config;
import appeng.api.config.Setting;
import appeng.api.config.YesNo;
import com.google.common.base.Preconditions;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
public final class Settings {
private static final Map<String, Setting<?>> SETTINGS = new HashMap<>();
public static final Setting<YesNo> ACCELERATE = register("accelerate", YesNo.NO, YesNo.YES);
private Settings() {
}
private synchronized static <T extends Enum<T>> Setting<T> register(String name, Class<T> enumClass) {
Preconditions.checkState(!SETTINGS.containsKey(name));
var setting = new Setting<>(name, enumClass);
SETTINGS.put(name, setting);
return setting;
}
@SafeVarargs
private synchronized static <T extends Enum<T>> Setting<T> register(String name, T firstOption, T... moreOptions) {
Preconditions.checkState(!SETTINGS.containsKey(name));
var setting = new Setting<T>(name, firstOption.getDeclaringClass(), EnumSet.of(firstOption, moreOptions));
SETTINGS.put(name, setting);
return setting;
}
public static Setting<?> getOrThrow(String name) {
var setting = SETTINGS.get(name);
if (setting == null) {
throw new IllegalArgumentException("Unknown setting '" + name + "'");
}
return setting;
}
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.content;
package com.extendedae_plus.ae.api.crafting;
import appeng.api.crafting.IPatternDetails;
import appeng.api.stacks.AEItemKey;

View File

@ -326,8 +326,11 @@ public class InfinityBigIntegerCellInventory implements StorageCell {
if (amount == 0){
return 0;
}
// 不允许存储无限单元自身
if (what instanceof AEItemKey itemKey && itemKey.getItem() instanceof InfinityBigIntegerCellItem) {
// 不允许存储有物品的无限单元
if (what instanceof AEItemKey itemKey &&
itemKey.getItem() instanceof InfinityBigIntegerCellItem &&
itemKey.hasTag()
) {
return 0;
}

View File

@ -1,6 +1,7 @@
package com.extendedae_plus;
package com.extendedae_plus.ae.client.gui;
import appeng.client.gui.style.Blitter;
import com.extendedae_plus.ExtendedAEPlus;
import net.minecraft.resources.ResourceLocation;
public class NewIcon {

View File

@ -9,129 +9,169 @@ import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen;
import com.extendedae_plus.config.ModConfig;
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 com.extendedae_plus.util.entitySpeed.ConfigParsingUtils;
import com.extendedae_plus.util.entitySpeed.PowerUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraftforge.registries.ForgeRegistries;
import java.util.List;
// 实体加速器菜单负责与客户端界面同步数据
/**
* 实体加速器菜单负责管理客户端与服务端的数据同步处理加速卡能量卡和目标方块的状态
*/
public class EntitySpeedTickerMenu extends UpgradeableMenu<EntitySpeedTickerPart> {
@GuiSync(716) public boolean accelerateEnabled = true;
// 已安装的实体加速卡数量用于能耗计算
@GuiSync(717) public int entitySpeedCardCount;
// 已安装的能量卡数量
@GuiSync(718) public int energyCardCount;
// 当前生效的配置倍率从配置中读取并同步
// 当前计算出的生效速度product of multipliers同步给客户端用于显示
@GuiSync(719) public int effectiveSpeed = 1;
@GuiSync(720) public double multiplier = 1.0;
@GuiSync(721) public boolean targetBlacklisted = false;
@GuiSync(716) public boolean accelerateEnabled = true; // 是否启用加速
@GuiSync(717) public int entitySpeedCardCount; // 已安装的实体加速卡数量
@GuiSync(718) public int energyCardCount; // 已安装的能量卡数量
@GuiSync(719) public int effectiveSpeed = 1; // 当前生效的加速倍率
@GuiSync(720) public double multiplier = 1.0; // 目标方块的配置倍率
@GuiSync(721) public boolean targetBlacklisted = false; // 目标方块是否在黑名单中
@GuiSync(722) public boolean networkEnergySufficient = true; // 网络能量是否充足
/**
* 构造函数初始化菜单并绑定部件
* @param id 菜单ID
* @param ip 玩家背包
* @param host 关联的实体加速器部件
*/
public EntitySpeedTickerMenu(int id, Inventory ip, EntitySpeedTickerPart host) {
super(ModMenuTypes.ENTITY_TICKER_MENU.get(), id, ip, host);
if (host != null) {
host.menu = this; // 绑定菜单到部件
this.accelerateEnabled = host.getAccelerateEnabled(); // 同步初始开关状态
}
}
/**
* 获取加速开关状态
* @return 是否启用加速
*/
public boolean getAccelerateEnabled() {
return this.accelerateEnabled;
}
/**
* 设置加速开关状态并同步到部件
* @param enabled 是否启用加速
*/
public void setAccelerateEnabled(boolean enabled) {
this.accelerateEnabled = enabled;
if (getHost() != null) {
getHost().setAccelerateEnabled(enabled); // 同步到部件
}
broadcastChanges(); // 广播状态变化
}
// 构造方法初始化菜单并与部件绑定
public EntitySpeedTickerMenu(int id, Inventory ip, EntitySpeedTickerPart host) {
super(ModMenuTypes.ENTITY_TICKER_MENU.get(), id, ip, host);
// 让部件持有当前菜单实例便于通信
getHost().menu = this;
// 初始同步部件上的开关状态到菜单服务器端构造时保证一致
try {
this.accelerateEnabled = getHost().getAccelerateEnabled();
} catch (Exception ignored) {}
/**
* 更新网络能量充足状态并广播到客户端
* @param sufficient 是否能量充足
*/
public void setNetworkEnergySufficient(boolean sufficient) {
this.networkEnergySufficient = sufficient;
broadcastChanges();
}
// 当服务器数据同步到客户端时调用
/**
* 服务端数据同步到客户端时调用更新卡数量目标状态和生效速度
*/
@Override
public void onServerDataSync() {
super.onServerDataSync();
// 重新统计实体加速卡和能量卡数量
updateCardCounts(); // 更新卡数量
updateTargetStatus(); // 更新目标方块的黑名单和倍率
updateEffectiveSpeed(); // 计算生效速度
updateNetworkEnergyStatus(); // 同步能量状态
if (isClientSide()) {
refreshClientGui(); // 客户端刷新界面
}
}
/**
* 当槽位内容变化时调用客户端更新卡数量和生效速度
* @param slot 发生变化的槽位
*/
@Override
public void onSlotChange(Slot slot) {
super.onSlotChange(slot);
if (isClientSide()) {
updateCardCounts();
updateEffectiveSpeed();
refreshClientGui();
}
}
/**
* 广播数据变化清理未启用槽位的显示堆栈
*/
@Override
public void broadcastChanges() {
for (Object o : this.slots) {
if (o instanceof OptionalFakeSlot fs && !fs.isSlotEnabled() && !fs.getDisplayStack().isEmpty()) {
fs.clearStack(); // 清理未启用槽位的显示
}
}
standardDetectAndSendChanges();
}
/**
* 更新加速卡和能量卡的数量
*/
private void updateCardCounts() {
this.entitySpeedCardCount = this.getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get());
this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
}
// 计算当前面向方块的倍率服务器端并同步给客户端
double mult = 1.0;
try {
BlockEntity target = getHost().getLevel().getBlockEntity(getHost().getBlockEntity().getBlockPos().relative(getHost().getSide()));
if (target != null) {
String blockId = ForgeRegistries.BLOCKS.getKey(target.getBlockState().getBlock()).toString();
for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(List.of(ModConfig.INSTANCE.entityTickerMultipliers))) {
if (me.pattern.matcher(blockId).matches()) {
mult = Math.max(mult, me.multiplier);
}
}
}
} catch (Exception ignored) {}
this.multiplier = mult;
// 检查目标是否在黑名单中如果是则标记并将生效速度设为 0服务器端计算
boolean blacklisted = false;
try {
BlockEntity target = getHost().getLevel().getBlockEntity(getHost().getBlockEntity().getBlockPos().relative(getHost().getSide()));
if (target != null) {
String blockId = ForgeRegistries.BLOCKS.getKey(target.getBlockState().getBlock()).toString();
for (java.util.regex.Pattern p : ConfigParsingUtils.getCachedBlacklist(List.of(ModConfig.INSTANCE.entityTickerBlackList))) {
if (p.matcher(blockId).matches()) {
blacklisted = true;
break;
}
}
}
} catch (Exception ignored) {}
this.targetBlacklisted = blacklisted;
// 计算生效速度如果被黑名单则为 0否则进行正常计算使用工具类从菜单直接计算 product with cap最多 8
if (this.targetBlacklisted) {
this.effectiveSpeed = 0;
} else {
this.effectiveSpeed = (int) PowerUtils.computeProductWithCapFromMenu(this, 8);
/**
* 更新目标方块的黑名单状态和倍率
*/
private void updateTargetStatus() {
BlockEntity target = getTargetBlockEntity();
if (target == null) {
this.multiplier = 1.0;
this.targetBlacklisted = false;
return;
}
String blockId = ForgeRegistries.BLOCKS.getKey(target.getBlockState().getBlock()).toString();
this.multiplier = ConfigParsingUtils.getMultiplierForBlock(blockId, List.of(ModConfig.INSTANCE.entityTickerMultipliers));
this.targetBlacklisted = ConfigParsingUtils.isBlockBlacklisted(blockId, List.of(ModConfig.INSTANCE.entityTickerBlackList));
}
// 如果在客户端刷新界面
if (isClientSide()) {
if (Minecraft.getInstance().screen instanceof EntitySpeedTickerScreen screen) {
screen.refreshGui();
}
/**
* 计算生效速度考虑黑名单和卡数量
*/
private void updateEffectiveSpeed() {
this.effectiveSpeed = targetBlacklisted ? 0 : (int) PowerUtils.computeProductWithCap(getUpgrades(), 8);
}
/**
* 同步网络能量状态仅服务端
*/
private void updateNetworkEnergyStatus() {
if (!isClientSide() && getHost() != null) {
this.networkEnergySufficient = getHost().isNetworkEnergySufficient();
}
}
// 当任意槽位发生变化时调用
@Override
public void onSlotChange(net.minecraft.world.inventory.Slot slot) {
super.onSlotChange(slot);
// 客户端重新统计卡数量并刷新界面
if (isClientSide()) {
this.entitySpeedCardCount = this.getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get());
this.energyCardCount = this.getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
// 立即在客户端计算生效速度以便界面即时反馈使用与服务端相同的工具方法最多 8 张卡
this.effectiveSpeed = (int) PowerUtils.computeProductWithCapFromMenu(this, 8);
if (Minecraft.getInstance().screen instanceof EntitySpeedTickerScreen screen) {
screen.refreshGui();
}
/**
* 客户端刷新界面
*/
private void refreshClientGui() {
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();
/**
* 获取目标方块实体
* @return 目标方块实体或 null
*/
private BlockEntity getTargetBlockEntity() {
return getHost() != null ?
getHost().getLevel().getBlockEntity(
getHost().getBlockEntity().getBlockPos().relative(getHost().getSide())
) : null;
}
}

View File

@ -2,14 +2,18 @@ package com.extendedae_plus.ae.parts;
import appeng.api.config.Actionable;
import appeng.api.config.PowerMultiplier;
import appeng.api.config.YesNo;
import appeng.api.networking.GridFlags;
import appeng.api.networking.IGridNode;
import appeng.api.networking.energy.IEnergyService;
import appeng.api.networking.security.IActionSource;
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.storage.MEStorage;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.core.definitions.AEItems;
import appeng.items.parts.PartModels;
@ -22,9 +26,8 @@ import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu;
import com.extendedae_plus.config.ModConfig;
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.core.BlockPos;
import com.extendedae_plus.util.entitySpeed.ConfigParsingUtils;
import com.extendedae_plus.util.entitySpeed.PowerUtils;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.InteractionHand;
@ -36,68 +39,86 @@ 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 net.minecraftforge.fml.ModList;
import net.minecraftforge.registries.ForgeRegistries;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
/**
* EntitySpeedTickerPart 是一个可升级的 AE2 部件<p>
* 该部件可以加速目标方块实体的 tick 速率消耗 AE 网络能量并支持加速卡升级<p>
* 功能受<a href="https://github.com/GilbertzRivi/crazyae2addons">Crazy AE2 Addons</a>启发
* 实体加速器部件用于加速目标方块实体的 tick 速率消耗 AE 网络能量支持加速卡和能量卡升级
* 灵感来源于 <a href="https://github.com/GilbertzRivi/crazyae2addons">Crazy AE2 Addons</a>
*/
public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTickable, MenuProvider, IUpgradeableObject {
// 当前打开的菜单实例如果有
public EntitySpeedTickerMenu menu;
public static final ResourceLocation MODEL_BASE = new ResourceLocation(
ExtendedAEPlus.MODID, "part/entity_speed_ticker_part");
@PartModels
public static final PartModel MODELS_OFF;
public static final PartModel MODELS_OFF = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_off"));
@PartModels
public static final PartModel MODELS_ON;
public static final PartModel MODELS_ON = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_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"));
}
public static final PartModel MODELS_HAS_CHANNEL = new PartModel(MODEL_BASE, new ResourceLocation(ExtendedAEPlus.MODID, "part/entity_speed_ticker_has_channel"));
public EntitySpeedTickerMenu menu; // 当前打开的菜单实例
private boolean networkEnergySufficient = true; // 网络能量是否充足
/**
* 构造函数初始化部件并设置网络节点属性
* 构造函数初始化部件并设置网络节点属性
* @param partItem 部件物品
*/
public EntitySpeedTickerPart(IPartItem<?> partItem) {
super(partItem);
// 设置网络节点属性需要通道空闲功耗为1并注册为 IGridTickable 服务
this.getMainNode()
.setFlags(GridFlags.REQUIRE_CHANNEL)
.setIdlePowerUsage(1)
.addService(IGridTickable.class, this);
// 注册可记忆的配置YES/NO
this.getConfigManager().registerSetting(
com.extendedae_plus.ae.api.config.Settings.ACCELERATE,
YesNo.YES
);
}
// 控制是否启用加速默认启用
private boolean accelerateEnabled = true;
public boolean getAccelerateEnabled() {
return this.accelerateEnabled;
}
public void setAccelerateEnabled(boolean accelerateEnabled) {
this.accelerateEnabled = accelerateEnabled;
return this.getConfigManager().getSetting(com.extendedae_plus.ae.api.config.Settings.ACCELERATE) == YesNo.YES;
}
/**
* 获取当前状态下的静态模型用于渲染
* 设置加速开关状态并通知菜单
* @param enabled 是否启用加速
*/
public void setAccelerateEnabled(boolean enabled) {
this.getConfigManager().putSetting(com.extendedae_plus.ae.api.config.Settings.ACCELERATE, enabled ? YesNo.YES : YesNo.NO);
// 是否启用加速
if (menu != null) {
menu.setAccelerateEnabled(enabled);
}
}
public boolean isNetworkEnergySufficient() {
return this.networkEnergySufficient;
}
/**
* 更新网络能量充足状态并通知菜单
* @param sufficient 是否能量充足
*/
private void updateNetworkEnergySufficient(boolean sufficient) {
this.networkEnergySufficient = sufficient;
if (menu != null) {
menu.setNetworkEnergySufficient(sufficient);
}
}
/**
* 获取当前状态的渲染模型
* @return 当前状态的模型
*/
@Override
public IPartModel getStaticModels() {
if (this.isActive() && this.isPowered()) {
return MODELS_HAS_CHANNEL;
@ -109,15 +130,14 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
}
/**
* 当玩家激活部件右键时调用打开自定义菜单
* 处理玩家右键激活部件打开菜单
* @param player 玩家
* @param hand
* @param pos 点击位置
* @return 总是返回 true表示激活成功
* @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));
}
@ -125,7 +145,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
}
/**
* 定义部件的碰撞箱用于物理碰撞和渲染
* 定义部件的碰撞箱
* @param bch 碰撞辅助器
*/
@Override
@ -135,43 +155,37 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
}
/**
* 获取定时请求决定本部件多久 tick 一次
* 获取定时请求指定 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();
if (menu != null) {
menu.broadcastChanges();
}
}
/**
* 网络定时回调每次 tick 时调用
* 网络定时回调处理目标方块实体的加速
* @param iGridNode 网络节点
* @param ticksSinceLastCall 距离上次调用经过 tick
* @return TickRateModulation.IDLE 表示继续保持当前 tick 速率
* @param ticksSinceLastCall 距离上次调用 tick
* @return TickRateModulation.IDLE
*/
@Override
public TickRateModulation tickingRequest(IGridNode iGridNode, int ticksSinceLastCall) {
// 如果部件的加速开关被关闭则不进行加速提前返回
if (!this.getAccelerateEnabled()) {
return TickRateModulation.IDLE;
}
// 获取目标方块实体本部件朝向的方块
BlockEntity target = getLevel().getBlockEntity(getBlockEntity().getBlockPos().relative(getSide()));
// 仅在目标存在且部件处于激活状态时执行加速
if (target != null && isActive()) {
ticker(target);
}
@ -179,78 +193,149 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
}
/**
* 以指定速度对目标方块实体进行 tick 操作
* @param blockEntity 需要被 tick 方块实体
* 对目标方块实体执行加速 tick 操作
* @param blockEntity 目标方块实体
* @param <T> 方块实体类型
*/
private <T extends BlockEntity> void ticker(@NotNull T blockEntity) {
if (this.getGridNode() == null
|| this.getMainNode() == null
|| this.getMainNode().getGrid() == null) {
if (!isValidForTicking()) {
return;
}
// 获取方块实体的位置
BlockPos pos = blockEntity.getBlockPos();
if (blockEntity.getLevel() == null) return;
// 检查黑名单支持通配符/正则
String blockId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString();
// 使用工具类的缓存接口工具类内部负责懒加载/线程安全
List<Pattern> compiledBlacklist = ConfigParsingUtils.getCachedBlacklist(List.of(ModConfig.INSTANCE.entityTickerBlackList));
for (Pattern p : compiledBlacklist) {
if (p.matcher(blockId).matches()) return;
String blockId = ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock()).toString();
if (ConfigParsingUtils.isBlockBlacklisted(blockId, List.of(ModConfig.INSTANCE.entityTickerBlackList))) {
return;
}
// 获取该方块实体的 Ticker
@SuppressWarnings("unchecked")
BlockEntityTicker<T> blockEntityTicker = this.getLevel()
.getBlockState(pos)
.getTicker(this.getLevel(), (BlockEntityType<T>) blockEntity.getType());
if (blockEntityTicker == null) return;
BlockEntityTicker<T> ticker = getTicker(blockEntity);
if (ticker == null) {
return;
}
// 使用集中定义的 CardDef 列表支持以后添加等级或改倍率而无需修改此逻辑
int energyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
int speed = calculateSpeed();
if (speed <= 0) {
return;
}
// 使用已注册的单一 Item 计算已安装卡数量总计用于能耗计算
double requiredPower = calculateRequiredPower(speed, blockId);
if (!extractPower(requiredPower)) {
return;
}
performTicks(blockEntity, ticker, speed);
}
/**
* 检查网络节点是否有效
* @return 是否可以执行 tick
*/
private boolean isValidForTicking() {
return getGridNode() != null && getMainNode() != null && getMainNode().getGrid() != null;
}
/**
* 获取目标方块实体的 ticker
* @param blockEntity 目标方块实体
* @return ticker null
*/
private <T extends BlockEntity> BlockEntityTicker<T> getTicker(T blockEntity) {
return getLevel().getBlockState(blockEntity.getBlockPos())
.getTicker(getLevel(), (BlockEntityType<T>) blockEntity.getType());
}
/**
* 计算加速倍率
* @return 生效的加速倍率
*/
private int calculateSpeed() {
int entitySpeedCardCount = getUpgrades().getInstalledUpgrades(ModItems.ENTITY_SPEED_CARD.get());
if (entitySpeedCardCount <= 0) return 0;
return (int) PowerUtils.computeProductWithCap(getUpgrades(), 8);
}
// 使用工具方法从槽位直接计算乘积并应用 cap最多 8 张卡
long product = PowerUtils.computeProductWithCapFromStacks(this.getUpgrades(), 8);
/**
* 计算所需能量
* @param speed 加速倍率
* @param blockId 目标方块ID
* @return 所需能量
*/
private double calculateRequiredPower(int speed, String blockId) {
int energyCardCount = getUpgrades().getInstalledUpgrades(AEItems.ENERGY_CARD);
double multiplier = ConfigParsingUtils.getMultiplierForBlock(blockId, List.of(ModConfig.INSTANCE.entityTickerMultipliers));
return PowerUtils.computeFinalPowerForProduct(speed, energyCardCount) * multiplier;
}
// 如果没有任何实体加速卡则不进行加速且不消耗额外能量只保留部件的被动功耗
if (entitySpeedCardCount <= 0) return;
/**
* 提取网络能量并更新状态优先从 AE2 网络提取 AE 能量不足时从磁盘提取 FE 能量
* @param requiredPower 所需能量AE 单位
* @return 是否成功提取足够能量
*/
private boolean extractPower(double requiredPower) {
IEnergyService energyService = getMainNode().getGrid().getEnergyService();
MEStorage storage = getMainNode().getGrid().getStorageService().getInventory();
IActionSource source = IActionSource.ofMachine(this);
boolean appFluxLoaded = ModList.get().isLoaded("appflux");
boolean preferDiskEnergy = appFluxLoaded && ModConfig.INSTANCE.prioritizeDiskEnergy;
// 计算本次 tick 所需能量使用工具类根据 product 计算最终能耗
double requiredPower = PowerUtils.computeFinalPowerForProduct(product, energyCardCount);
int speed = (int) product;
double multiplier = 1.0;
for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(List.of(ModConfig.INSTANCE.entityTickerMultipliers))) {
if (me.pattern.matcher(blockId).matches()) {
multiplier = Math.max(multiplier, me.multiplier);
// 如果 appflux 存在且优先磁盘能量尝试提取 FE 能量
if (appFluxLoaded && preferDiskEnergy) {
if (tryExtractFE(energyService, storage, requiredPower, source)) {
return true;
}
}
requiredPower *= multiplier;
// 尝试提取 AE 能量 appflux 不存在优先 AE 能量或 FE 提取失败时
double simulated = energyService.extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG);
if (simulated >= requiredPower) {
double extracted = energyService.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
boolean sufficient = extracted >= requiredPower;
updateNetworkEnergySufficient(sufficient);
return sufficient;
}
updateNetworkEnergySufficient(false);
// 先模拟提取以检查网络中是否有足够能量再真正抽取
double simulated = getMainNode().getGrid().getEnergyService()
.extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG);
if (simulated < requiredPower) return;
// 如果 appflux 存在且优先 AE 能量尝试提取 FE 能量作为备用
if (appFluxLoaded && !preferDiskEnergy) {
return tryExtractFE(energyService, storage, requiredPower, source);
}
return false;
}
double extractedPower = getMainNode().getGrid().getEnergyService()
.extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG);
if (extractedPower < requiredPower) return;
private boolean tryExtractFE(IEnergyService energyService, MEStorage storage, double requiredPower, IActionSource source) {
try {
Class<?> helperClass = Class.forName("com.extendedae_plus.util.FluxEnergyHelper");
Method extractMethod = helperClass.getMethod(
"extractFE",
IEnergyService.class,
MEStorage.class,
long.class,
IActionSource.class
);
long feRequired = (long) requiredPower << 1; // 1 AE = 2 FE
long feExtracted = (long) extractMethod.invoke(null, energyService, storage, feRequired, source);
if (feExtracted >= feRequired) {
updateNetworkEnergySufficient(true);
return true;
}
} catch (Exception e) {
// 如果反射失败视为 FE 不可用
}
updateNetworkEnergySufficient(false);
return false;
}
// 计算加速倍数基于 2 的次方并把 8 张映射到最大 1024x2^10
// 已由 product 计算得到 speed上面已在没有卡时提前返回
// 执行 tick 操作
/**
* 执行加速 tick 操作
* @param blockEntity 目标方块实体
* @param ticker 方块实体 ticker
* @param speed 加速倍率
*/
private <T extends BlockEntity> void performTicks(T blockEntity,
BlockEntityTicker<T> ticker,
int speed) {
// 执行 speed-1 次额外 tick原生 tick 已包含 1
for (int i = 0; i < speed - 1; i++) {
blockEntityTicker.tick(
ticker.tick(
blockEntity.getLevel(),
blockEntity.getBlockPos(),
blockEntity.getBlockState(),
@ -259,26 +344,18 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
}
}
/**
* 判断部件是否有自定义名称
* @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 玩家
@ -292,7 +369,7 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka
}
/**
* 获取可用的升级卡槽数量
* 获取升级卡槽数量
* @return 升级卡槽数量
*/
@Override

View File

@ -11,125 +11,115 @@ import appeng.util.Platform;
import com.extendedae_plus.ae.menu.EntitySpeedTickerMenu;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.network.ToggleEntityTickerC2SPacket;
import com.extendedae_plus.util.PowerUtils;
import com.extendedae_plus.util.entitySpeed.PowerUtils;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 实体加速器界面显示加速状态卡数量能耗和倍率信息
*/
public class EntitySpeedTickerScreen<C extends EntitySpeedTickerMenu> extends UpgradeableScreen<C> {
private boolean eap$entitySpeedTickerEnabled = false;
private SettingToggleButton<YesNo> eap$entitySpeedTickerToggle;
private boolean eap$entitySpeedTickerEnabled = false; // 本地缓存的加速开关状态
private final SettingToggleButton<YesNo> eap$entitySpeedTickerToggle; // 加速开关按钮
public EntitySpeedTickerScreen(
EntitySpeedTickerMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
/**
* 构造函数初始化界面和控件
* @param menu 实体加速器菜单
* @param playerInventory 玩家背包
* @param title 界面标题
* @param style 界面样式
*/
public EntitySpeedTickerScreen(EntitySpeedTickerMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
super((C) menu, playerInventory, title, style);
this.addToLeftToolbar(CommonButtons.togglePowerUnit());
this.addToLeftToolbar(CommonButtons.togglePowerUnit()); // 添加功率单位切换按钮
this.eap$entitySpeedTickerEnabled = menu.getAccelerateEnabled();
try{
this.eap$entitySpeedTickerEnabled = menu.getAccelerateEnabled();
}catch (Exception ignored){}
// 使用 SettingToggleButton<YesNo> 的外观原版图标但自定义悬停描述为智能阻挡
// 不做本地切换点击仅发送自定义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());
}
(btn, backwards) ->
ModNetwork.CHANNEL.sendToServer(new ToggleEntityTickerC2SPacket())
) {
@Override
public List<Component> getTooltipMessage() {
// 如果目标在黑名单中直接显示已禁用的提示
try {
if (menu != null && menu.targetBlacklisted) {
var title = Component.literal("实体加速");
var stateLine = Component.literal("已禁用(目标在黑名单)");
return List.of(title, stateLine);
}
} catch (Exception ignored) {}
if (menu.targetBlacklisted) {
return List.of(
Component.literal("实体加速"),
Component.literal("已禁用(目标在黑名单)")
);
}
boolean enabled = eap$entitySpeedTickerEnabled;
var title = Component.literal("实体加速");
var stateLine = enabled
? Component.literal("已启用: 将加速目标方块实体的tick")
: Component.literal("已关闭: 不会对目标方块实体进行加速");
return List.of(title, stateLine);
return List.of(
Component.literal("实体加速"),
enabled ? Component.literal("已启用: 将加速目标方块实体的tick") :
Component.literal("已关闭: 不会对目标方块实体进行加速")
);
}
@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;
}
if (menu.targetBlacklisted) return Icon.INVALID;
return this.getCurrentValue() == YesNo.YES ? Icon.VALID : Icon.INVALID;
}
};
// 初始化后立刻对齐当前@GuiSync状态避免首帧显示不一致
eap$entitySpeedTickerToggle.set(this.eap$entitySpeedTickerEnabled ? YesNo.YES : YesNo.NO);
this.addToLeftToolbar(eap$entitySpeedTickerToggle);
}
/**
* 在渲染前更新界面状态
*/
@Override
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;
// 如果目标在黑名单中禁用切换并强制显示为关闭
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;
}
if (eap$entitySpeedTickerToggle != null && menu != null) {
eap$entitySpeedTickerEnabled = menu.getAccelerateEnabled();
// 如果目标在黑名单禁用按钮并显示关闭状态
eap$entitySpeedTickerToggle.set(menu.targetBlacklisted ? YesNo.NO : (eap$entitySpeedTickerEnabled ? YesNo.YES : YesNo.NO));
eap$entitySpeedTickerToggle.active = !menu.targetBlacklisted;
}
textData();
}
/**
* 刷新界面显示
*/
public void refreshGui() {
textData();
}
/**
* 更新界面文本内容包括加速状态速度能耗和倍率
*/
private void textData() {
// 如果目标被黑名单禁止则显示禁用状态并把数值显示为 0
Map<String, Component> textContents = new HashMap<>();
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;
// 黑名单禁用时的默认显示
textContents.put("enable", Component.translatable("screen.extendedae_plus.entity_speed_ticker.enable"));
textContents.put("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", 0));
textContents.put("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(0.0, false)));
textContents.put("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(0.0)));
textContents.put("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", 0.0)));
} else {
// 正常状态下显示实际数据
int energyCardCount = getMenu().energyCardCount;
double multiplier = getMenu().multiplier;
int effectiveSpeed = getMenu().effectiveSpeed;
double finalPower = PowerUtils.computeFinalPowerForProduct(effectiveSpeed, energyCardCount);
double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount);
textContents.put("enable", getMenu().networkEnergySufficient ? null :
Component.translatable("screen.extendedae_plus.entity_speed_ticker.warning_network_energy_insufficient"));
textContents.put("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", effectiveSpeed));
textContents.put("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(finalPower, false)));
textContents.put("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio)));
textContents.put("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", multiplier)));
}
int energyCardCount = getMenu().energyCardCount;
double multiplier = getMenu().multiplier;
int effectiveSpeed = getMenu().effectiveSpeed;
double finalPower = PowerUtils.computeFinalPowerForProduct(effectiveSpeed, energyCardCount);
double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount);
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)));
textContents.forEach(this::setTextContent);
}
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless;
package com.extendedae_plus.ae.wireless;
import appeng.api.networking.IGridNode;
import net.minecraft.core.BlockPos;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless;
package com.extendedae_plus.ae.wireless;
import net.minecraft.server.level.ServerLevel;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless;
package com.extendedae_plus.ae.wireless;
import com.extendedae_plus.config.ModConfig;
import net.minecraft.resources.ResourceKey;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.wireless;
package com.extendedae_plus.ae.wireless;
import appeng.api.networking.GridHelper;
import appeng.api.networking.IGridNode;

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.wireless.endpoint;
package com.extendedae_plus.ae.wireless.endpoint;
import appeng.api.networking.IGridNode;
import com.extendedae_plus.wireless.IWirelessEndpoint;
import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;

View File

@ -1,8 +1,8 @@
package com.extendedae_plus.wireless.endpoint;
package com.extendedae_plus.ae.wireless.endpoint;
import appeng.api.networking.IGridNode;
import appeng.helpers.InterfaceLogicHost;
import com.extendedae_plus.wireless.IWirelessEndpoint;
import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.Level;

View File

@ -1,6 +1,6 @@
package com.extendedae_plus.api;
public interface AdvancedBlockingHolder {
public interface IAdvancedBlocking {
boolean eap$getAdvancedBlocking();
void eap$setAdvancedBlocking(boolean value);

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.api;
/**
* {@code GuiExPatternProviderMixin} 实现用于从通用的 Screen Mixin 中更新按钮布局
*/
public interface ExPatternButtonsAccessor {
public interface IExPatternButtonsAccessor {
/**
* 在每帧调用以维护扩展样板供应器右侧按钮的可见性重注册窗口尺寸变化与定位
*/

View File

@ -3,6 +3,6 @@ package com.extendedae_plus.api;
/**
* GuiExPatternProviderMixin 实现用于在客户端侧提供当前页号避免反射读取 AE2 内部字段失败
*/
public interface ExPatternPageAccessor {
public interface IExPatternPageAccessor {
int eap$getCurrentPage();
}

View File

@ -1,5 +1,5 @@
package com.extendedae_plus.api;
public interface PatternProviderMenuAdvancedSync {
public interface IPatternProviderMenuAdvancedSync {
boolean eap$getAdvancedBlockingSynced();
}

View File

@ -1,5 +0,0 @@
package com.extendedae_plus.api;
public interface PatternProviderMenuDoublingSync {
boolean eap$getSmartDoublingSynced();
}

View File

@ -1,6 +0,0 @@
package com.extendedae_plus.api;
public interface SmartDoublingAwarePattern {
boolean eap$allowScaling();
void eap$setAllowScaling(boolean allow);
}

View File

@ -1,6 +0,0 @@
package com.extendedae_plus.api;
public interface SmartDoublingHolder {
boolean eap$getSmartDoubling();
void eap$setSmartDoubling(boolean value);
}

View File

@ -1,9 +1,9 @@
package com.extendedae_plus.bridge;
package com.extendedae_plus.api.bridge;
/**
* mixin 包下的桥接接口 mixin 进行 instanceof 检测和回调
*/
public interface InterfaceWirelessLinkBridge {
public interface IInterfaceWirelessLinkBridge {
void eap$updateWirelessLink();
/**

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.bridge;
package com.extendedae_plus.api.bridge;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.menu.ToolboxMenu;

View File

@ -0,0 +1,5 @@
package com.extendedae_plus.api.smartDoubling;
public interface IPatternProviderMenuDoublingSync {
boolean eap$getSmartDoublingSynced();
}

View File

@ -0,0 +1,6 @@
package com.extendedae_plus.api.smartDoubling;
public interface ISmartDoublingAwarePattern {
boolean eap$allowScaling();
void eap$setAllowScaling(boolean allow);
}

View File

@ -0,0 +1,6 @@
package com.extendedae_plus.api.smartDoubling;
public interface ISmartDoublingHolder {
boolean eap$getSmartDoubling();
void eap$setSmartDoubling(boolean value);
}

View File

@ -8,8 +8,8 @@ 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.extendedae_plus.network.crafting.OpenCraftFromJeiC2SPacket;
import com.glodblock.github.extendedae.client.gui.GuiExPatternTerminal;
import mezz.jei.api.ingredients.ITypedIngredient;
import net.minecraft.client.Minecraft;
@ -17,8 +17,8 @@ import net.minecraft.client.gui.screens.Screen;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ScreenEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.common.Mod;
import org.lwjgl.glfw.GLFW;
import java.util.Optional;

View File

@ -2,7 +2,7 @@ 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.provider.GlobalToggleProviderModesC2SPacket;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.network.chat.Component;

View File

@ -2,7 +2,6 @@ package com.extendedae_plus.compat;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.api.upgrades.UpgradeInventories;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.ToolboxPanel;
import appeng.client.gui.widgets.UpgradesPanel;
@ -41,12 +40,7 @@ public class UpgradeSlotCompat {
*/
public static boolean shouldEnableUpgradeSlots() {
boolean appfluxExists = isAppfluxPresent();
if (appfluxExists) {
return false;
} else {
return true;
}
return !appfluxExists;
}
/**
@ -97,8 +91,6 @@ public class UpgradeSlotCompat {
if (menu instanceof IUpgradeableMenuCompat compatMenu) {
compatMenu.setCompatToolbox(toolbox);
}
ExtendedAELogger.LOGGER.debug("成功为PatternProviderMenu初始化升级功能");
return true;
}
} catch (Exception e) {
@ -144,8 +136,6 @@ public class UpgradeSlotCompat {
ToolboxPanel toolboxPanel = new ToolboxPanel(style, toolbox.getName());
addMethod.invoke(widgets, "toolbox", toolboxPanel);
}
ExtendedAELogger.LOGGER.debug("成功为PatternProviderScreen添加升级面板");
return true;
} catch (NoSuchMethodException e) {
// 尝试其他可能的方法签名
@ -170,8 +160,6 @@ public class UpgradeSlotCompat {
ToolboxPanel toolboxPanel = new ToolboxPanel(style, toolbox.getName());
putMethod.invoke(widgets, "toolbox", toolboxPanel);
}
ExtendedAELogger.LOGGER.debug("成功为PatternProviderScreen添加升级面板使用put方法");
return true;
} catch (Exception e2) {
ExtendedAELogger.LOGGER.error("反射调用widgets方法失败", e2);

View File

@ -125,4 +125,11 @@ public final class ModConfig {
@Configurable.Range(min = 100, max = Integer.MAX_VALUE)
public int craftingPauseThreshold = 100000;
@Configurable
@Configurable.Comment(value = {
"是否优先从磁盘提取FE能量仅当Applied Flux模组存在时生效",
"开启后将优先尝试从磁盘提取FE能量反之优先消耗AE网络中的能量"
})
@Configurable.Synchronized
public boolean prioritizeDiskEnergy = true;
}

View File

@ -3,11 +3,11 @@ package com.extendedae_plus.content.wireless;
import appeng.api.networking.*;
import appeng.api.util.AECableType;
import appeng.blockentity.AEBaseBlockEntity;
import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import com.extendedae_plus.ae.wireless.WirelessMasterLink;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.init.ModBlockEntities;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.IWirelessEndpoint;
import com.extendedae_plus.wireless.WirelessMasterLink;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;

View File

@ -2,6 +2,11 @@ package com.extendedae_plus.init;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.network.*;
import com.extendedae_plus.network.crafting.CraftingMonitorJumpC2SPacket;
import com.extendedae_plus.network.crafting.CraftingMonitorOpenProviderC2SPacket;
import com.extendedae_plus.network.crafting.OpenCraftFromJeiC2SPacket;
import com.extendedae_plus.network.meInterface.InterfaceAdjustConfigAmountC2SPacket;
import com.extendedae_plus.network.provider.*;
import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.network.NetworkDirection;
import net.minecraftforge.network.NetworkRegistry;

View File

@ -6,14 +6,8 @@ import appeng.core.definitions.AEItems;
import appeng.core.definitions.AEParts;
import appeng.core.localization.GuiText;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.EX_PATTERN_PROVIDER;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.EX_PATTERN_PROVIDER_PART;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.EX_INTERFACE;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.EX_INTERFACE_PART;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.OVERSIZE_INTERFACE;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.OVERSIZE_INTERFACE_PART;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.EX_IMPORT_BUS;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.EX_EXPORT_BUS;
import static com.glodblock.github.extendedae.common.EPPItemAndBlock.*;
/**
*

View File

@ -2,9 +2,9 @@ package com.extendedae_plus.integration.jade;
import appeng.api.networking.IGrid;
import appeng.api.networking.IGridNode;
import com.extendedae_plus.ae.wireless.IWirelessEndpoint;
import com.extendedae_plus.ae.wireless.WirelessMasterRegistry;
import com.extendedae_plus.content.wireless.WirelessTransceiverBlockEntity;
import com.extendedae_plus.wireless.IWirelessEndpoint;
import com.extendedae_plus.wireless.WirelessMasterRegistry;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;

View File

@ -1,6 +1,5 @@
package com.extendedae_plus.mixin;
import net.minecraftforge.fml.ModList;
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
@ -27,7 +26,6 @@ public class MixinConditions implements IMixinConfigPlugin {
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
// 对于升级相关的Mixin检查appflux是否存在
if (mixinClassName.contains("PatternProviderMenuUpgradesMixin") ||
mixinClassName.contains("PatternProviderScreenUpgradesMixin") ||
mixinClassName.contains("PatternProviderLogicUpgradesMixin") ||
mixinClassName.contains("PatternProviderLogicHostUpgradesMixin")) {

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.mixin.advancedae;
import appeng.api.crafting.IPatternDetails;
import com.extendedae_plus.content.ScaledProcessingPattern;
import com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

View File

@ -5,18 +5,17 @@ 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.api.IExPatternButtonsAccessor;
import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket;
import com.extendedae_plus.network.provider.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.provider.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;
@ -45,15 +44,15 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
@Unique
private boolean eap$SmartDoublingEnabled = false;
public AdvPatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super((AdvPatternProviderMenu) menu, playerInventory, title, style);
public AdvPatternProviderScreenMixin(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
@Inject(method = "<init>", at = @At("RETURN"))
private void eap$initAdvancedBlocking(AdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 使用 @GuiSync 初始化
try {
if (menu instanceof PatternProviderMenuAdvancedSync sync) {
if (menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced();
}
} catch (Throwable t) {
@ -86,7 +85,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
// 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动
try {
if (menu instanceof PatternProviderMenuDoublingSync sync2) {
if (menu instanceof IPatternProviderMenuDoublingSync sync2) {
this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced();
}
} catch (Throwable t) {
@ -120,7 +119,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
private void eap$updateAdvancedBlocking(CallbackInfo ci) {
if (this.eap$AdvancedBlockingToggle != null) {
boolean desired = this.eap$AdvancedBlockingEnabled;
if (this.menu instanceof PatternProviderMenuAdvancedSync sync) {
if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
desired = sync.eap$getAdvancedBlockingSynced();
}
this.eap$AdvancedBlockingEnabled = desired;
@ -129,7 +128,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
if (this.eap$SmartDoublingToggle != null) {
boolean desired2 = this.eap$SmartDoublingEnabled;
if (this.menu instanceof PatternProviderMenuDoublingSync sync2) {
if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) {
desired2 = sync2.eap$getSmartDoublingSynced();
}
this.eap$SmartDoublingEnabled = desired2;
@ -138,7 +137,7 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen<AdvPatt
if ((Object) this instanceof GuiExPatternProvider) {
try {
((ExPatternButtonsAccessor) this).eap$updateButtonsLayout();
((IExPatternButtonsAccessor) this).eap$updateButtonsLayout();
} catch (Throwable t) {
LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString());
}

View File

@ -5,18 +5,17 @@ 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.api.IExPatternButtonsAccessor;
import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket;
import com.extendedae_plus.network.provider.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.provider.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;
@ -45,15 +44,15 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
@Unique
private boolean eap$SmartDoublingEnabled = false;
public SmallAdvPatternProviderScreenMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super((SmallAdvPatternProviderMenu) menu, playerInventory, title, style);
public SmallAdvPatternProviderScreenMixin(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
@Inject(method = "<init>", at = @At("RETURN"))
private void eap$initAdvancedBlocking(SmallAdvPatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 使用 @GuiSync 初始化
try {
if (menu instanceof PatternProviderMenuAdvancedSync sync) {
if (menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced();
}
} catch (Throwable t) {
@ -86,7 +85,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
// 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动
try {
if (menu instanceof PatternProviderMenuDoublingSync sync2) {
if (menu instanceof IPatternProviderMenuDoublingSync sync2) {
this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced();
}
} catch (Throwable t) {
@ -120,7 +119,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
private void eap$updateAdvancedBlocking(CallbackInfo ci) {
if (this.eap$AdvancedBlockingToggle != null) {
boolean desired = this.eap$AdvancedBlockingEnabled;
if (this.menu instanceof PatternProviderMenuAdvancedSync sync) {
if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
desired = sync.eap$getAdvancedBlockingSynced();
}
this.eap$AdvancedBlockingEnabled = desired;
@ -129,7 +128,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
if (this.eap$SmartDoublingToggle != null) {
boolean desired2 = this.eap$SmartDoublingEnabled;
if (this.menu instanceof PatternProviderMenuDoublingSync sync2) {
if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) {
desired2 = sync2.eap$getSmartDoublingSynced();
}
this.eap$SmartDoublingEnabled = desired2;
@ -138,7 +137,7 @@ public abstract class SmallAdvPatternProviderScreenMixin extends AEBaseScreen<Sm
if ((Object) this instanceof GuiExPatternProvider) {
try {
((ExPatternButtonsAccessor) this).eap$updateButtonsLayout();
((IExPatternButtonsAccessor) this).eap$updateButtonsLayout();
} catch (Throwable t) {
LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString());
}

View File

@ -5,7 +5,7 @@ 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 com.extendedae_plus.api.IAdvancedBlocking;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.player.Player;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collections;
@Mixin(value = AdvPatternProviderLogic.class, remap = false)
public class AdvPatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder {
public class AdvPatternProviderLogicAdvancedMixin implements IAdvancedBlocking {
@Unique
private static final String EAP_ADV_BLOCKING_KEY = "eap_advanced_blocking";

View File

@ -2,8 +2,8 @@ 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.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderLogicPatternsAccessor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.player.Player;
@ -16,7 +16,7 @@ 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 {
public class AdvPatternProviderLogicDoublingMixin implements ISmartDoublingHolder {
@Unique
private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling";
@ -35,7 +35,7 @@ public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder
try {
var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns();
for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) {
if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(value);
}
}
@ -63,7 +63,7 @@ public class AdvPatternProviderLogicDoublingMixin implements SmartDoublingHolder
var list = ((AdvPatternProviderLogicPatternsAccessor) this).eap$patterns();
boolean allow = this.eap$smartDoubling;
for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) {
if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(allow);
}
}

View File

@ -2,8 +2,8 @@ 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 com.extendedae_plus.api.IAdvancedBlocking;
import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AdvPatternProviderMenu.class)
public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync {
public abstract class AdvPatternProviderMenuAdvancedMixin implements IPatternProviderMenuAdvancedSync {
@Final
@Shadow(remap = false)
protected AdvPatternProviderLogic logic;
@ -33,7 +33,7 @@ public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProv
// 避免@Shadow父类方法改用公共APIAEBaseMenu#isClientSide()
if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) {
if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
}
}
@ -44,7 +44,7 @@ public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProv
private void eap$initAdvancedSync_Public(int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) {
try {
var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) {
if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
}
} catch (Throwable ignored) {}
@ -55,7 +55,7 @@ public abstract class AdvPatternProviderMenuAdvancedMixin implements PatternProv
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) {
if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
}
} catch (Throwable ignored) {}

View File

@ -2,8 +2,8 @@ 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 com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import net.pedroksl.advanced_ae.common.logic.AdvPatternProviderLogic;
@ -18,7 +18,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(AdvPatternProviderMenu.class)
public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync {
public abstract class AdvPatternProviderMenuDoublingMixin implements IPatternProviderMenuDoublingSync {
@Final
@Shadow(remap = false)
protected AdvPatternProviderLogic logic;
@ -31,7 +31,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProv
private void eap$syncSmartDoubling(CallbackInfo ci) {
if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic;
if (l instanceof SmartDoublingHolder holder) {
if (l instanceof ISmartDoublingHolder holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling();
}
}
@ -41,7 +41,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProv
private void eap$initSmartSync_Public(int id, Inventory playerInventory, AdvPatternProviderLogicHost host, CallbackInfo ci) {
try {
var l = this.logic;
if (l instanceof SmartDoublingHolder holder) {
if (l instanceof ISmartDoublingHolder holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling();
}
} catch (Throwable ignored) {}
@ -51,7 +51,7 @@ public abstract class AdvPatternProviderMenuDoublingMixin implements PatternProv
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) {
if (l instanceof ISmartDoublingHolder holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling();
}
} catch (Throwable ignored) {}

View File

@ -1,12 +1,12 @@
package com.extendedae_plus.mixin.ae2;
import appeng.crafting.pattern.AEProcessingPattern;
import com.extendedae_plus.api.SmartDoublingAwarePattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@Mixin(value = AEProcessingPattern.class, remap = false)
public class AEProcessingPatternMixin implements SmartDoublingAwarePattern {
public class AEProcessingPatternMixin implements ISmartDoublingAwarePattern {
@Unique
private boolean eap$allowScaling = false; // 默认不允许缩放

View File

@ -1,10 +0,0 @@
package com.extendedae_plus.mixin.ae2.accessor;
import appeng.client.gui.AEBaseScreen;
import appeng.menu.AEBaseMenu;
import org.spongepowered.asm.mixin.Mixin;
@Mixin(AEBaseScreen.class)
public interface AEBaseScreenInvoker<T extends AEBaseMenu> {
// 空接口避免在 AEBaseScreen 上声明不存在方法的 Invoker 导致编译错误
}

View File

@ -1,11 +1,14 @@
package com.extendedae_plus.mixin.ae2.accessor;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.IManagedGridNode;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(PatternProviderLogic.class)
public interface PatternProviderLogicAccessor {
@Accessor(value = "host", remap = false)
@ -13,4 +16,7 @@ public interface PatternProviderLogicAccessor {
@Accessor(value = "mainNode", remap = false)
IManagedGridNode eap$mainNode();
@Accessor(value = "patterns" , remap = false)
List<IPatternDetails> eap$patterns();
}

View File

@ -1,14 +0,0 @@
package com.extendedae_plus.mixin.ae2.accessor;
import appeng.api.stacks.AEKey;
import appeng.helpers.patternprovider.PatternProviderLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.Set;
@Mixin(PatternProviderLogic.class)
public interface PatternProviderLogicPatternInputsAccessor {
@Accessor(value = "patternInputs",remap = false)
Set<AEKey> eap$patternInputs();
}

View File

@ -1,14 +0,0 @@
package com.extendedae_plus.mixin.ae2.accessor;
import appeng.api.crafting.IPatternDetails;
import appeng.helpers.patternprovider.PatternProviderLogic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
import java.util.List;
@Mixin(value = PatternProviderLogic.class, remap = false)
public interface PatternProviderLogicPatternsAccessor {
@Accessor("patterns")
List<IPatternDetails> eap$patterns();
}

View File

@ -6,7 +6,7 @@ import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(PatternProviderMenu.class)
public interface PatternProviderMenuAdvancedAccessor {
public interface PatternProviderMenuAccessor {
@Accessor(value = "logic", remap = false)
PatternProviderLogic eap$logic();
}

View File

@ -2,7 +2,7 @@ package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.crafting.IPatternDetails;
import appeng.me.service.CraftingService;
import com.extendedae_plus.content.ScaledProcessingPattern;
import com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyArg;

View File

@ -3,14 +3,14 @@ package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.stacks.KeyCounter;
import appeng.crafting.CraftingTreeNode;
import appeng.crafting.inv.CraftingSimulationState;
import com.extendedae_plus.util.RequestedAmountHolder;
import com.extendedae_plus.util.smartDoubling.RequestedAmountHolder;
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 org.spongepowered.asm.mixin.injection.callback.LocalCapture;
@Mixin(value = CraftingTreeNode.class,remap = false)
@Mixin(value = CraftingTreeNode.class, remap = false)
public class CraftingTreeNodeMixin {
@Inject(method = "request(Lappeng/crafting/inv/CraftingSimulationState;JLappeng/api/stacks/KeyCounter;)V",
at = @At(value = "INVOKE",
@ -18,13 +18,6 @@ public class CraftingTreeNodeMixin {
locals = LocalCapture.CAPTURE_FAILHARD)
private void captureRequestedAmount(CraftingSimulationState inv, long requestedAmount, KeyCounter containerItems, CallbackInfo ci) {
// push the requestedAmount before addContainerItems is called
RequestedAmountHolder.push(requestedAmount);
}
@Inject(method = "request(Lappeng/crafting/inv/CraftingSimulationState;JLappeng/api/stacks/KeyCounter;)V",
at = @At(value = "RETURN"))
private void clearRequestedAmountOnReturn(CraftingSimulationState inv, long requestedAmount, KeyCounter containerItems, CallbackInfo ci) {
// pop the pushed requested amount on return
RequestedAmountHolder.pop();
RequestedAmountHolder.push(requestedAmount);
}
}

View File

@ -9,11 +9,11 @@ import appeng.crafting.CraftingTreeNode;
import appeng.crafting.CraftingTreeProcess;
import appeng.crafting.pattern.AEProcessingPattern;
import appeng.me.service.CraftingService;
import com.extendedae_plus.api.SmartDoublingAwarePattern;
import com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.config.ModConfig;
import com.extendedae_plus.content.ScaledProcessingPattern;
import com.extendedae_plus.util.PatternScaler;
import com.extendedae_plus.util.RequestedAmountHolder;
import com.extendedae_plus.util.smartDoubling.PatternScaler;
import com.extendedae_plus.util.smartDoubling.RequestedAmountHolder;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
@ -41,7 +41,7 @@ public abstract class CraftingTreeProcessMixin {
// 若传入的 details 已经是缩放样板且原始样板不允许缩放则直接解包为原始样板
if (details instanceof ScaledProcessingPattern sp) {
var proc0 = sp.getOriginal();
if (proc0 instanceof SmartDoublingAwarePattern aware0 && !aware0.eap$allowScaling()) {
if (proc0 instanceof ISmartDoublingAwarePattern aware0 && !aware0.eap$allowScaling()) {
return proc0;
}
}
@ -49,13 +49,14 @@ public abstract class CraftingTreeProcessMixin {
if (!(details instanceof AEProcessingPattern proc)) return original;
// 若样板标记为不允许缩放则直接跳过
if (proc instanceof SmartDoublingAwarePattern aware && !aware.eap$allowScaling()) {
if (proc instanceof ISmartDoublingAwarePattern aware && !aware.eap$allowScaling()) {
return original;
}
CraftingTreeNodeAccessor parentAcc = (CraftingTreeNodeAccessor) craftingTreeNode;
AEKey parentTarget = parentAcc.eap$getWhat();
long requested = RequestedAmountHolder.get();
RequestedAmountHolder.pop();
// 根据配置决定是否在 provider 间轮询分配请求量默认开启
long perProvider = 1L;

View File

@ -2,7 +2,7 @@ package com.extendedae_plus.mixin.ae2.autopattern;
import appeng.api.crafting.IPatternDetails;
import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.content.ScaledProcessingPattern;
import com.extendedae_plus.ae.api.crafting.ScaledProcessingPattern;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

View File

@ -13,14 +13,14 @@ import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.style.Text;
import appeng.client.gui.style.TextAlignment;
import appeng.menu.slot.AppEngSlot;
import com.extendedae_plus.api.ExPatternPageAccessor;
import com.extendedae_plus.api.IExPatternPageAccessor;
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.mixin.ae2.accessor.AEBaseScreenAccessor;
import com.extendedae_plus.network.crafting.CraftingMonitorJumpC2SPacket;
import com.extendedae_plus.network.crafting.CraftingMonitorOpenProviderC2SPacket;
import com.extendedae_plus.util.GuiUtil;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import com.mojang.logging.LogUtils;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
@ -40,17 +40,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(AEBaseScreen.class)
public abstract class AEBaseScreenMixin {
@Unique
private ScreenStyle eap$getStyle(Object self) {
try {
var f = self.getClass().getDeclaredField("style");
f.setAccessible(true);
Object v = f.get(self);
if (v instanceof ScreenStyle s) return s;
} catch (Throwable ignored) {}
return null;
}
/**
* AEBaseScreen mouseClicked 入口拦截 CraftingCPUScreen Shift+左键
* 读取鼠标下的 AEKey 并发送 CraftingMonitorJumpC2SPacket
@ -77,8 +66,7 @@ public abstract class AEBaseScreenMixin {
}
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorJumpC2SPacket(key));
cir.setReturnValue(true);
} catch (Throwable ignored) {
}
} catch (Throwable ignored) {}
}
/**
@ -107,8 +95,7 @@ public abstract class AEBaseScreenMixin {
}
ModNetwork.CHANNEL.sendToServer(new CraftingMonitorOpenProviderC2SPacket(key));
cir.setReturnValue(true);
} catch (Throwable ignored) {
}
} catch (Throwable ignored) {}
}
@Unique
@ -266,7 +253,7 @@ public abstract class AEBaseScreenMixin {
int cur = 1;
int max = 1;
if (self instanceof ExPatternPageAccessor accessor) {
if (self instanceof IExPatternPageAccessor accessor) {
cur = Math.max(0, accessor.eap$getCurrentPage()) + 1;
}
try {
@ -281,7 +268,7 @@ public abstract class AEBaseScreenMixin {
String pageText = "" + cur + "" + "/" + max + "";
ScreenStyle style = eap$getStyle(self);
ScreenStyle style = ((AEBaseScreenAccessor<?>) this).eap$getStyle();
int color = 0xFFFFFFFF;
if (style != null) {
try {
@ -299,11 +286,9 @@ public abstract class AEBaseScreenMixin {
guiGraphics.drawString(font, pageText, lineWidth + padding, 0, color, false);
guiGraphics.pose().popPose();
}
} catch (Throwable ignored) {
}
} catch (Throwable ignored) {}
}
@Shadow(remap = false)
protected void setTextContent(String id, Component content) {};

View File

@ -3,17 +3,15 @@ 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.init.ModNetwork;
import com.extendedae_plus.network.InterfaceAdjustConfigAmountC2SPacket;
import appeng.menu.SlotSemantics;
import net.minecraft.world.inventory.Slot;
import appeng.menu.implementations.InterfaceMenu;
import com.extendedae_plus.ae.client.gui.NewIcon;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.mixin.accessor.AbstractContainerScreenAccessor;
import com.extendedae_plus.mixin.accessor.ScreenAccessor;
import com.extendedae_plus.network.meInterface.InterfaceAdjustConfigAmountC2SPacket;
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 net.minecraft.world.inventory.Slot;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@ -170,7 +168,7 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
// 获取菜单与配置槽列表
var screen = (AEBaseScreen<?>) (Object) this;
var menu = screen.getMenu();
if (!(menu instanceof appeng.menu.implementations.InterfaceMenu interfaceMenu)) {
if (!(menu instanceof InterfaceMenu interfaceMenu)) {
return;
}
var configSlots = interfaceMenu.getSlots(SlotSemantics.CONFIG);
@ -273,7 +271,7 @@ public abstract class InterfaceScreenMixin<T extends AEBaseMenu> {
}
var screen = (AEBaseScreen<?>) (Object) this;
var menu = screen.getMenu();
if (!(menu instanceof appeng.menu.implementations.InterfaceMenu interfaceMenu)) {
if (!(menu instanceof InterfaceMenu interfaceMenu)) {
return;
}
var configSlots = interfaceMenu.getSlots(SlotSemantics.CONFIG);

View File

@ -11,6 +11,7 @@ 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.provider.RequestProvidersListC2SPacket;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.renderer.Rect2i;
@ -41,7 +42,7 @@ public abstract class PatternEncodingTermScreenMixin<T extends AEBaseMenu> {
// 复用已存在的按钮实例避免重复创建
if (eap$uploadBtn == null) {
eap$uploadBtn = new IconButton(btn -> ModNetwork.CHANNEL
.sendToServer(new com.extendedae_plus.network.RequestProvidersListC2SPacket())) {
.sendToServer(new RequestProvidersListC2SPacket())) {
private final float eap$scale = 0.75f; // 12x12
@Override

View File

@ -16,7 +16,6 @@ public class PatternProviderCloseMixin {
if (((Object) this) instanceof PatternProviderScreen) {
ClientPatternHighlightStore.clearAll();
}
} catch (Throwable ignored) {
}
} catch (Throwable ignored) {}
}
}

View File

@ -7,12 +7,12 @@ import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.SettingToggleButton;
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.api.IExPatternButtonsAccessor;
import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.network.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.ToggleSmartDoublingC2SPacket;
import com.extendedae_plus.network.provider.ToggleAdvancedBlockingC2SPacket;
import com.extendedae_plus.network.provider.ToggleSmartDoublingC2SPacket;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
@ -52,7 +52,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
private void eap$initAdvancedBlocking(C menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 使用 @GuiSync 初始化
try {
if (menu instanceof PatternProviderMenuAdvancedSync sync) {
if (menu instanceof IPatternProviderMenuAdvancedSync sync) {
this.eap$AdvancedBlockingEnabled = sync.eap$getAdvancedBlockingSynced();
}
} catch (Throwable t) {
@ -85,7 +85,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
// 智能翻倍按钮与高级阻挡同款样式点击仅发送C2S状态由@GuiSync驱动
try {
if (menu instanceof PatternProviderMenuDoublingSync sync2) {
if (menu instanceof IPatternProviderMenuDoublingSync sync2) {
this.eap$SmartDoublingEnabled = sync2.eap$getSmartDoublingSynced();
}
} catch (Throwable t) {
@ -119,7 +119,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
private void eap$updateAdvancedBlocking(CallbackInfo ci) {
if (this.eap$AdvancedBlockingToggle != null) {
boolean desired = this.eap$AdvancedBlockingEnabled;
if (this.menu instanceof PatternProviderMenuAdvancedSync sync) {
if (this.menu instanceof IPatternProviderMenuAdvancedSync sync) {
desired = sync.eap$getAdvancedBlockingSynced();
}
this.eap$AdvancedBlockingEnabled = desired;
@ -128,7 +128,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
if (this.eap$SmartDoublingToggle != null) {
boolean desired2 = this.eap$SmartDoublingEnabled;
if (this.menu instanceof PatternProviderMenuDoublingSync sync2) {
if (this.menu instanceof IPatternProviderMenuDoublingSync sync2) {
desired2 = sync2.eap$getSmartDoublingSynced();
}
this.eap$SmartDoublingEnabled = desired2;
@ -137,7 +137,7 @@ public abstract class PatternProviderScreenMixin<C extends PatternProviderMenu>
if ((Object) this instanceof GuiExPatternProvider) {
try {
((ExPatternButtonsAccessor) this).eap$updateButtonsLayout();
((IExPatternButtonsAccessor) this).eap$updateButtonsLayout();
} catch (Throwable t) {
LOGGER.debug("[EAP] updateButtonsLayout skipped: {}", t.toString());
}

View File

@ -1,54 +0,0 @@
package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.api.upgrades.Upgrades;
import appeng.client.gui.AEBaseScreen;
import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.client.gui.style.ScreenStyle;
import appeng.client.gui.widgets.ToolboxPanel;
import appeng.client.gui.widgets.UpgradesPanel;
import appeng.core.localization.GuiText;
import appeng.menu.SlotSemantics;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.bridge.IUpgradableMenu;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
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 java.util.ArrayList;
import java.util.List;
@Mixin(value = PatternProviderScreen.class, priority = 2000, remap = false)
public abstract class PatternProviderScreenUpgradesMixin<C extends PatternProviderMenu> extends AEBaseScreen<C> {
@Inject(method = "<init>", at = @At("TAIL"))
private void eap$initUpgrades(PatternProviderMenu menu, Inventory playerInventory, Component title, ScreenStyle style, CallbackInfo ci) {
// 只有在应该启用升级卡槽时才添加升级面板
if (!UpgradeSlotCompat.shouldAddUpgradePanelToScreen()) {
return;
}
this.widgets.add("upgrades", new UpgradesPanel(
menu.getSlots(SlotSemantics.UPGRADE),
this::eap$getCompatibleUpgrades));
if (((IUpgradableMenu) menu).getToolbox() != null && ((IUpgradableMenu) menu).getToolbox().isPresent()) {
this.widgets.add("toolbox", new ToolboxPanel(style, ((IUpgradableMenu) menu).getToolbox().getName()));
}
}
@Unique
private List<Component> eap$getCompatibleUpgrades() {
var list = new ArrayList<Component>();
list.add(GuiText.CompatibleUpgrades.text());
list.addAll(Upgrades.getTooltipLinesForMachine(((IUpgradableMenu) menu).getUpgrades().getUpgradableItem()));
return list;
}
public PatternProviderScreenUpgradesMixin(C menu, Inventory playerInventory, Component title, ScreenStyle style) {
super(menu, playerInventory, title, style);
}
}

View File

@ -2,6 +2,7 @@ package com.extendedae_plus.mixin.ae2.client.gui;
import appeng.client.Point;
import appeng.client.gui.layout.SlotGridLayout;
import com.extendedae_plus.api.IExPatternPageAccessor;
import net.minecraft.client.Minecraft;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@ -32,7 +33,7 @@ public abstract class SlotGridLayoutMixin {
// 读取实际当前页码优先从 GUI accessor其次反射容器失败则为 0
int currentPage = 0;
try {
if (screen instanceof com.extendedae_plus.api.ExPatternPageAccessor accessor) {
if (screen instanceof IExPatternPageAccessor accessor) {
currentPage = accessor.eap$getCurrentPage();
} else {
var menu = ((com.glodblock.github.extendedae.client.gui.GuiExPatternProvider) screen).getMenu();

View File

@ -8,11 +8,11 @@ import appeng.api.upgrades.UpgradeInventories;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Final;
@ -31,7 +31,7 @@ import java.util.List;
* 根据appflux是否存在来决定是否实现IUpgradeableObject接口
*/
@Mixin(value = PatternProviderLogic.class, priority = 500, remap = false)
public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObject, InterfaceWirelessLinkBridge {
public abstract class PatternProviderLogicCompatMixin implements IUpgradeableObject, IInterfaceWirelessLinkBridge {
@Unique
private IUpgradeInventory eap$compatUpgrades = UpgradeInventories.empty();

View File

@ -4,11 +4,10 @@ import appeng.api.upgrades.IUpgradeInventory;
import appeng.helpers.InterfaceLogic;
import appeng.helpers.InterfaceLogicHost;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.ae.wireless.endpoint.InterfaceNodeEndpointImpl;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.InterfaceNodeEndpointImpl;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -18,7 +17,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(InterfaceLogic.class)
public abstract class InterfaceLogicChannelCardMixin implements InterfaceWirelessLinkBridge {
public abstract class InterfaceLogicChannelCardMixin implements IInterfaceWirelessLinkBridge {
@Shadow(remap = false) public abstract IUpgradeInventory getUpgrades();

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.bridge;
package com.extendedae_plus.api.bridge;
/**
* 旧名兼容已迁移到非 mixin 避免 Mixin 处理器禁止直接引用

View File

@ -1,8 +1,7 @@
package com.extendedae_plus.mixin.ae2.helpers;
import appeng.helpers.InterfaceLogic;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -29,7 +28,7 @@ public abstract class InterfaceLogicTickerMixin {
return;
}
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) {
if (this$0 instanceof IInterfaceWirelessLinkBridge bridge) {
// 处理延迟初始化
bridge.eap$handleDelayedInit();
}
@ -38,7 +37,7 @@ public abstract class InterfaceLogicTickerMixin {
@Inject(method = "tickingRequest", at = @At("TAIL"), remap = false)
private void eap$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall,
CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) {
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) {
if (this$0 instanceof IInterfaceWirelessLinkBridge bridge) {
bridge.eap$updateWirelessLink();
}
}

View File

@ -6,7 +6,7 @@ import appeng.api.stacks.AEKey;
import appeng.api.stacks.GenericStack;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderTarget;
import com.extendedae_plus.api.AdvancedBlockingHolder;
import com.extendedae_plus.api.IAdvancedBlocking;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.Collections;
@Mixin(value = PatternProviderLogic.class, remap = false)
public class PatternProviderLogicAdvancedMixin implements AdvancedBlockingHolder {
public class PatternProviderLogicAdvancedMixin implements IAdvancedBlocking {
@Unique
private static final String EAP_ADV_BLOCKING_KEY = "eap_advanced_blocking";

View File

@ -3,9 +3,9 @@ package com.extendedae_plus.mixin.ae2.helpers;
import appeng.api.crafting.IPatternDetails;
import appeng.crafting.pattern.AEProcessingPattern;
import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.api.SmartDoublingAwarePattern;
import com.extendedae_plus.api.SmartDoublingHolder;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicPatternsAccessor;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.player.Player;
import org.spongepowered.asm.mixin.Mixin;
@ -16,7 +16,7 @@ import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = PatternProviderLogic.class, remap = false)
public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder {
public class PatternProviderLogicDoublingMixin implements ISmartDoublingHolder {
@Unique
private static final String EAP_SMART_DOUBLING_KEY = "eap_smart_doubling";
@ -33,9 +33,9 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder {
this.eap$smartDoubling = value;
// 立即将开关状态应用到当前 Provider 的样板上避免等待下一次 updatePatterns
try {
var list = ((PatternProviderLogicPatternsAccessor) this).eap$patterns();
var list = ((PatternProviderLogicAccessor) this).eap$patterns();
for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) {
if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(value);
}
}
@ -60,10 +60,10 @@ public class PatternProviderLogicDoublingMixin implements SmartDoublingHolder {
@Inject(method = "updatePatterns", at = @At("TAIL"))
private void eap$applySmartDoublingToPatterns(CallbackInfo ci) {
try {
var list = ((PatternProviderLogicPatternsAccessor) this).eap$patterns();
var list = ((PatternProviderLogicAccessor) this).eap$patterns();
boolean allow = this.eap$smartDoubling;
for (IPatternDetails details : list) {
if (details instanceof AEProcessingPattern proc && proc instanceof SmartDoublingAwarePattern aware) {
if (details instanceof AEProcessingPattern proc && proc instanceof ISmartDoublingAwarePattern aware) {
aware.eap$setAllowScaling(allow);
}
}

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.mixin.ae2.helpers.patternprovider;
import appeng.helpers.patternprovider.PatternProviderLogic;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@ -27,7 +27,7 @@ public abstract class PatternProviderLogicTickerMixin {
if (node != null && node.getLevel() != null && node.getLevel().isClientSide) {
return;
}
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) {
if (this$0 instanceof IInterfaceWirelessLinkBridge bridge) {
bridge.eap$handleDelayedInit();
}
}
@ -35,7 +35,7 @@ public abstract class PatternProviderLogicTickerMixin {
@Inject(method = "tickingRequest", at = @At("TAIL"))
private void eap$tickTail(appeng.api.networking.IGridNode node, int ticksSinceLastCall,
CallbackInfoReturnable<appeng.api.networking.ticking.TickRateModulation> cir) {
if (this$0 instanceof InterfaceWirelessLinkBridge bridge) {
if (this$0 instanceof IInterfaceWirelessLinkBridge bridge) {
bridge.eap$updateWirelessLink();
}
}

View File

@ -0,0 +1,223 @@
package com.extendedae_plus.mixin.ae2.items;
import appeng.api.inventories.InternalInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.core.localization.PlayerMessages;
import appeng.items.tools.MemoryCardItem;
import appeng.items.tools.NetworkToolItem;
import appeng.util.inv.PlayerInternalInventory;
import com.extendedae_plus.ae.parts.EntitySpeedTickerPart;
import com.extendedae_plus.init.ModItems;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.ListTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.BlockEntity;
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 org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import java.util.ArrayList;
@Mixin(value = MemoryCardItem.class, remap = false)
public class MemoryCardItemMixin {
/**
* 写入 Memory Card 时保留实体加速卡的完整 NBT 数据
*/
@Inject(method = "storeUpgrades", at = @At("HEAD"), cancellable = true)
private static void storeUpgradesCustom(IUpgradeableObject upgradeableObject, CompoundTag output, CallbackInfo ci) {
try {
CompoundTag desiredUpgradesTag = new CompoundTag();
ListTag entitySpeedCards = new ListTag();
InternalInventory upgrades = upgradeableObject.getUpgrades();
for (int i = 0; i < upgrades.size(); i++) {
ItemStack upgradeStack = upgrades.getStackInSlot(i);
if (upgradeStack.isEmpty()) continue;
ResourceLocation itemId = BuiltInRegistries.ITEM.getKey(upgradeStack.getItem());
String key = itemId.toString();
if (upgradeStack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) {
CompoundTag stackTag = new CompoundTag();
stackTag.putInt("Slot", i);
upgradeStack.save(stackTag);
entitySpeedCards.add(stackTag);
} else {
desiredUpgradesTag.putInt(key, desiredUpgradesTag.getInt(key) + upgradeStack.getCount());
}
}
if (!entitySpeedCards.isEmpty()) {
desiredUpgradesTag.put("entity_speed_cards", entitySpeedCards);
}
output.put("upgrades", desiredUpgradesTag);
ci.cancel();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Memory Card 恢复升级时从玩家背包或网络工具提取实体加速卡
*/
@Inject(method = "restoreUpgrades", at = @At("HEAD"), cancellable = true)
private static void restoreUpgradesCustom(Player player, CompoundTag input, IUpgradeableObject upgradeableObject, CallbackInfoReturnable<Boolean> cir) {
try {
if (!input.contains("upgrades")) {
cir.setReturnValue(false);
return;
}
CompoundTag desiredUpgradesTag = input.getCompound("upgrades");
InternalInventory upgrades = upgradeableObject.getUpgrades();
// 收集背包和网络工具作为升级卡来源
var upgradeSources = new ArrayList<InternalInventory>();
upgradeSources.add(new PlayerInternalInventory(player.getInventory()));
var networkTool = NetworkToolItem.findNetworkToolInv(player);
if (networkTool != null) {
upgradeSources.add(networkTool.getInventory());
}
// 清空所有槽位中的 EntitySpeedCardItem
for (int i = 0; i < upgrades.size(); i++) {
ItemStack stack = upgrades.getStackInSlot(i);
if (!stack.isEmpty() && stack.getItem().equals(ModItems.ENTITY_SPEED_CARD.get())) {
ItemStack removed = upgrades.extractItem(i, stack.getCount(), false);
for (var source : upgradeSources) {
if (!removed.isEmpty()) {
removed = source.addItems(removed);
}
}
if (!removed.isEmpty()) {
player.drop(removed, false);
}
}
}
// 恢复 EntitySpeedCardItem
if (desiredUpgradesTag.contains("entity_speed_cards", Tag.TAG_LIST)) {
ListTag entitySpeedCards = desiredUpgradesTag.getList("entity_speed_cards", Tag.TAG_COMPOUND);
for (int i = 0; i < entitySpeedCards.size(); i++) {
CompoundTag stackTag = entitySpeedCards.getCompound(i);
ItemStack desiredStack = ItemStack.of(stackTag);
int slot = stackTag.contains("Slot") ? stackTag.getInt("Slot") : i;
if (player.getAbilities().instabuild) {
// 创造模式直接生成
if (slot >= 0 && slot < upgrades.size()) {
upgrades.setItemDirect(slot, desiredStack);
} else {
upgrades.addItems(desiredStack);
}
} else {
// 非创造模式从背包或网络工具提取
int missingAmount = desiredStack.getCount();
ItemStack extracted = ItemStack.EMPTY;
for (var source : upgradeSources) {
ItemStack potential = new ItemStack(desiredStack.getItem(), missingAmount);
if (desiredStack.hasTag()) {
potential.setTag(desiredStack.getTag().copy());
}
ItemStack cards = source.removeItems(missingAmount, potential, null);
if (!cards.isEmpty()) {
ItemStack overflow = upgrades.addItems(cards);
if (!overflow.isEmpty()) {
player.getInventory().placeItemBackInInventory(overflow);
}
missingAmount -= cards.getCount();
extracted = cards;
}
if (missingAmount <= 0) break;
}
if (missingAmount > 0 && !player.level().isClientSide()) {
player.displayClientMessage(
PlayerMessages.MissingUpgrades.text(desiredStack.getItem().getDescription(), missingAmount),
true
);
} else if (!extracted.isEmpty()) {
if (slot >= 0 && slot < upgrades.size()) {
upgrades.setItemDirect(slot, extracted);
} else {
upgrades.addItems(extracted);
}
}
}
}
}
// 恢复其他升级卡 AE2 原逻辑
for (String key : desiredUpgradesTag.getAllKeys()) {
ResourceLocation id;
try {
id = new ResourceLocation(key);
} catch (Exception ex) {
continue;
}
var item = BuiltInRegistries.ITEM.getOptional(id).orElse(null);
if (item == null || item.equals(ModItems.ENTITY_SPEED_CARD.get())) continue;
int desiredCount = desiredUpgradesTag.getInt(key);
if (desiredCount > 0) {
if (player.getAbilities().instabuild) {
// 创造模式直接生成
ItemStack stack = new ItemStack(item, desiredCount);
upgrades.addItems(stack);
} else {
// 非创造模式从背包或网络工具提取
int missingAmount = desiredCount;
ItemStack potential = new ItemStack(item, missingAmount);
ItemStack overflow = upgrades.addItems(potential, true);
if (!overflow.isEmpty()) {
missingAmount -= overflow.getCount();
}
for (var source : upgradeSources) {
ItemStack cards = source.removeItems(missingAmount, potential, null);
if (!cards.isEmpty()) {
overflow = upgrades.addItems(cards);
if (!overflow.isEmpty()) {
player.getInventory().placeItemBackInInventory(overflow);
}
missingAmount -= cards.getCount();
}
if (missingAmount <= 0) break;
}
if (missingAmount > 0 && !player.level().isClientSide()) {
player.displayClientMessage(
PlayerMessages.MissingUpgrades.text(item.getDescription(), missingAmount),
true
);
}
}
}
}
// 标记保存并通知升级变化
if (upgradeableObject instanceof EntitySpeedTickerPart speedTickerPart) {
BlockEntity be = speedTickerPart.getBlockEntity();
if (be != null) {
be.setChanged();
}
speedTickerPart.upgradesChanged();
}
cir.setReturnValue(true);
} catch (Exception e) {
e.printStackTrace();
cir.setReturnValue(false);
}
}
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.mixin.ae2;
package com.extendedae_plus.mixin.ae2.items;
import appeng.api.parts.IPartHost;
import appeng.api.parts.SelectedPart;

View File

@ -5,8 +5,8 @@ import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu;
import appeng.menu.guisync.GuiSync;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.AdvancedBlockingHolder;
import com.extendedae_plus.api.PatternProviderMenuAdvancedSync;
import com.extendedae_plus.api.IAdvancedBlocking;
import com.extendedae_plus.api.IPatternProviderMenuAdvancedSync;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import org.spongepowered.asm.mixin.Final;
@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
@Mixin(PatternProviderMenu.class)
public abstract class PatternProviderMenuAdvancedMixin implements PatternProviderMenuAdvancedSync {
public abstract class PatternProviderMenuAdvancedMixin implements IPatternProviderMenuAdvancedSync {
@Final
@Shadow(remap = false)
protected PatternProviderLogic logic;
@ -35,7 +35,7 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide
// 避免@Shadow父类方法改用公共APIAEBaseMenu#isClientSide()
if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) {
if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
}
}
@ -46,7 +46,7 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide
private void eap$initAdvancedSync_Public(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
try {
var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) {
if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
}
} catch (Throwable ignored) {}
@ -57,7 +57,7 @@ public abstract class PatternProviderMenuAdvancedMixin implements PatternProvide
private void eap$initAdvancedSync_Protected(MenuType<? extends PatternProviderMenu> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
try {
var l = this.logic;
if (l instanceof AdvancedBlockingHolder holder) {
if (l instanceof IAdvancedBlocking holder) {
this.eap$AdvancedBlocking = holder.eap$getAdvancedBlocking();
}
} catch (Throwable t) {

View File

@ -5,8 +5,8 @@ import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu;
import appeng.menu.guisync.GuiSync;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.PatternProviderMenuDoublingSync;
import com.extendedae_plus.api.SmartDoublingHolder;
import com.extendedae_plus.api.smartDoubling.IPatternProviderMenuDoublingSync;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;
import org.spongepowered.asm.mixin.Final;
@ -20,7 +20,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
@Mixin(PatternProviderMenu.class)
public abstract class PatternProviderMenuDoublingMixin implements PatternProviderMenuDoublingSync {
public abstract class PatternProviderMenuDoublingMixin implements IPatternProviderMenuDoublingSync {
@Final
@Shadow(remap = false)
protected PatternProviderLogic logic;
@ -33,7 +33,7 @@ public abstract class PatternProviderMenuDoublingMixin implements PatternProvide
private void eap$syncSmartDoubling(CallbackInfo ci) {
if (!((AEBaseMenu) (Object) this).isClientSide()) {
var l = this.logic;
if (l instanceof SmartDoublingHolder holder) {
if (l instanceof ISmartDoublingHolder holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling();
}
}
@ -43,7 +43,7 @@ public abstract class PatternProviderMenuDoublingMixin implements PatternProvide
private void eap$initSmartSync_Public(int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
try {
var l = this.logic;
if (l instanceof SmartDoublingHolder holder) {
if (l instanceof ISmartDoublingHolder holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling();
}
} catch (Throwable t) {
@ -55,7 +55,7 @@ public abstract class PatternProviderMenuDoublingMixin implements PatternProvide
private void eap$initSmartSync_Protected(MenuType<? extends PatternProviderMenu> menuType, int id, Inventory playerInventory, PatternProviderLogicHost host, CallbackInfo ci) {
try {
var l = this.logic;
if (l instanceof SmartDoublingHolder holder) {
if (l instanceof ISmartDoublingHolder holder) {
this.eap$SmartDoubling = holder.eap$getSmartDoubling();
}
} catch (Throwable t) {

View File

@ -7,7 +7,7 @@ import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.menu.AEBaseMenu;
import appeng.menu.ToolboxMenu;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.bridge.IUpgradableMenu;
import com.extendedae_plus.api.bridge.IUpgradableMenu;
import com.extendedae_plus.compat.UpgradeSlotCompat;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.MenuType;

View File

@ -1,7 +1,7 @@
package com.extendedae_plus.mixin.ae2.parts;
import appeng.parts.AEBasePart;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import net.minecraft.network.FriendlyByteBuf;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@ -18,8 +18,8 @@ public class AEBasePartClientSyncMixin {
@Inject(method = "writeToStream", at = @At("TAIL"))
private void eap$writeWirelessState(FriendlyByteBuf data, CallbackInfo ci) {
// 检查是否实现了无线链接桥接接口
if (this instanceof InterfaceWirelessLinkBridge) {
InterfaceWirelessLinkBridge bridge = (InterfaceWirelessLinkBridge) this;
if (this instanceof IInterfaceWirelessLinkBridge) {
IInterfaceWirelessLinkBridge bridge = (IInterfaceWirelessLinkBridge) this;
// 同步无线连接状态到客户端
boolean connected = false;
try {
@ -44,8 +44,8 @@ public class AEBasePartClientSyncMixin {
boolean connected = data.readBoolean();
// 检查是否实现了无线链接桥接接口
if (this instanceof InterfaceWirelessLinkBridge) {
InterfaceWirelessLinkBridge bridge = (InterfaceWirelessLinkBridge) this;
if (this instanceof IInterfaceWirelessLinkBridge) {
IInterfaceWirelessLinkBridge bridge = (IInterfaceWirelessLinkBridge) this;
try {
// 更新客户端状态
bridge.eap$setClientWirelessState(connected);

View File

@ -3,16 +3,14 @@ package com.extendedae_plus.mixin.ae2.parts.automation;
import appeng.api.networking.security.IActionHost;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.helpers.InterfaceLogicHost;
import appeng.parts.automation.IOBusPart;
import net.minecraft.nbt.CompoundTag;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import net.minecraft.network.FriendlyByteBuf;
import com.extendedae_plus.util.ExtendedAELogger;
import net.minecraft.nbt.CompoundTag;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@ -23,7 +21,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* AE2 I/O 总线注入频道卡联动在升级变更时读取频道并更新无线链接
*/
@Mixin(value = IOBusPart.class, remap = false)
public abstract class IOBusPartChannelCardMixin implements InterfaceWirelessLinkBridge, IUpgradeableObject {
public abstract class IOBusPartChannelCardMixin implements IInterfaceWirelessLinkBridge, IUpgradeableObject {
@Unique
private WirelessSlaveLink eap$link;

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.mixin.ae2.parts.automation;
import appeng.api.networking.IGridNode;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.parts.automation.IOBusPart;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -17,7 +17,7 @@ public abstract class IOBusPartTickerChannelCardMixin {
@Inject(method = "tickingRequest", at = @At("TAIL"))
private void eap$tickTail(IGridNode node, int ticksSinceLastCall, CallbackInfoReturnable<TickRateModulation> cir) {
if (this instanceof InterfaceWirelessLinkBridge bridge) {
if (this instanceof IInterfaceWirelessLinkBridge bridge) {
bridge.eap$updateWirelessLink();
}
}

View File

@ -5,14 +5,13 @@ import appeng.api.networking.security.IActionHost;
import appeng.api.upgrades.IUpgradeInventory;
import appeng.api.upgrades.IUpgradeableObject;
import appeng.parts.storagebus.StorageBusPart;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.FriendlyByteBuf;
import com.extendedae_plus.util.ExtendedAELogger;
import com.extendedae_plus.ae.items.ChannelCardItem;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.ae.wireless.WirelessSlaveLink;
import com.extendedae_plus.ae.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import com.extendedae_plus.init.ModItems;
import com.extendedae_plus.wireless.WirelessSlaveLink;
import com.extendedae_plus.wireless.endpoint.GenericNodeEndpointImpl;
import com.extendedae_plus.util.ExtendedAELogger;
import net.minecraft.nbt.CompoundTag;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
@ -23,7 +22,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
* AE2 的存储总线注入频道卡联动在升级变更时读取频道并更新无线链接
*/
@Mixin(value = StorageBusPart.class, remap = false)
public abstract class StorageBusPartChannelCardMixin implements InterfaceWirelessLinkBridge, IUpgradeableObject {
public abstract class StorageBusPartChannelCardMixin implements IInterfaceWirelessLinkBridge, IUpgradeableObject {
@Unique
private WirelessSlaveLink eap$link;

View File

@ -3,7 +3,7 @@ package com.extendedae_plus.mixin.ae2.parts.storagebus;
import appeng.api.networking.IGridNode;
import appeng.api.networking.ticking.TickRateModulation;
import appeng.parts.storagebus.StorageBusPart;
import com.extendedae_plus.bridge.InterfaceWirelessLinkBridge;
import com.extendedae_plus.api.bridge.IInterfaceWirelessLinkBridge;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@ -17,7 +17,7 @@ public abstract class StorageBusPartTickerChannelCardMixin {
@Inject(method = "tickingRequest", at = @At("TAIL"))
private void eap$tickTail(IGridNode node, int ticksSinceLastCall, CallbackInfoReturnable<TickRateModulation> cir) {
if (this instanceof InterfaceWirelessLinkBridge bridge) {
if (this instanceof IInterfaceWirelessLinkBridge bridge) {
bridge.eap$updateWirelessLink();
}
}

View File

@ -4,8 +4,9 @@ import appeng.client.gui.Icon;
import appeng.client.gui.implementations.PatternProviderScreen;
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.ae.client.gui.NewIcon;
import com.extendedae_plus.api.IExPatternButtonsAccessor;
import com.extendedae_plus.api.IExPatternPageAccessor;
import com.extendedae_plus.config.ModConfig;
import com.glodblock.github.extendedae.client.button.ActionEPPButton;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;
@ -26,7 +27,7 @@ import java.lang.reflect.Method;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
@Mixin(GuiExPatternProvider.class)
public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements ExPatternButtonsAccessor, com.extendedae_plus.api.ExPatternPageAccessor {
public abstract class GuiExPatternProviderMixin extends PatternProviderScreen<ContainerExPatternProvider> implements IExPatternButtonsAccessor, IExPatternPageAccessor {
@Unique
ScreenStyle eap$screenStyle;

View File

@ -11,7 +11,7 @@ import appeng.menu.AEBaseMenu;
import com.extendedae_plus.config.ModConfig;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.mixin.extendedae.accessor.GuiExPatternTerminalAccessor;
import com.extendedae_plus.network.OpenProviderUiC2SPacket;
import com.extendedae_plus.network.provider.OpenProviderUiC2SPacket;
import com.extendedae_plus.util.GuiUtil;
import com.glodblock.github.extendedae.client.gui.GuiExPatternTerminal;
import net.minecraft.client.Minecraft;

View File

@ -1,8 +1,7 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.crafting;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.IGrid;
import appeng.api.networking.crafting.ICraftingProvider;
import appeng.api.networking.security.IActionHost;
import appeng.api.stacks.AEKey;
import appeng.helpers.patternprovider.PatternProviderLogic;
@ -18,7 +17,6 @@ import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkEvent;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.crafting;
import appeng.api.crafting.IPatternDetails;
import appeng.api.networking.IGrid;
@ -13,6 +13,8 @@ import appeng.menu.me.crafting.CraftingCPUMenu;
import appeng.parts.AEBasePart;
import com.extendedae_plus.init.ModNetwork;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderLogicAccessor;
import com.extendedae_plus.network.SetPatternHighlightS2CPacket;
import com.extendedae_plus.network.provider.SetProviderPageS2CPacket;
import com.extendedae_plus.util.PatternProviderDataUtil;
import com.glodblock.github.extendedae.util.FCClientUtil;
import com.glodblock.github.glodium.util.GlodUtil;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.crafting;
import appeng.api.networking.IGrid;
import appeng.api.stacks.AEKey;

View File

@ -1,8 +1,7 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.meInterface;
import appeng.menu.implementations.InterfaceMenu;
import appeng.menu.SlotSemantics;
import appeng.api.stacks.GenericStack;
import appeng.menu.implementations.InterfaceMenu;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import com.extendedae_plus.client.ClientAdvancedBlockingState;
import net.minecraft.network.FriendlyByteBuf;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import appeng.api.config.Settings;
import appeng.api.config.YesNo;
@ -7,8 +7,8 @@ import appeng.blockentity.crafting.PatternProviderBlockEntity;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.helpers.patternprovider.PatternProviderLogicHost;
import appeng.parts.crafting.PatternProviderPart;
import com.extendedae_plus.api.AdvancedBlockingHolder;
import com.extendedae_plus.api.SmartDoublingHolder;
import com.extendedae_plus.api.IAdvancedBlocking;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.content.controller.NetworkPatternControllerBlockEntity;
import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
@ -16,15 +16,15 @@ import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
import java.util.Set;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
/**
* C2S全网批量切换样板供应器的三种模式
* - 阻挡模式AE2 内置 BLOCKING_MODE 设置
* - 高级阻挡模式AdvancedBlockingHolder mixin
* - 智能翻倍模式SmartDoublingHolder mixin
* - 高级阻挡模式IAdvancedBlocking mixin
* - 智能翻倍模式ISmartDoublingHolder mixin
*
* 负载为三个操作码各1字节分别对应blockingadvancedBlockingsmartDoubling
*/
@ -173,14 +173,14 @@ public class GlobalToggleProviderModesC2SPacket {
}
}
// 2) 高级阻挡mixin 接口
if (msg.opAdvancedBlocking != Op.NOOP && logic instanceof AdvancedBlockingHolder adv) {
if (msg.opAdvancedBlocking != Op.NOOP && logic instanceof IAdvancedBlocking adv) {
boolean current = adv.eap$getAdvancedBlocking();
boolean target = computeTarget(current, msg.opAdvancedBlocking);
adv.eap$setAdvancedBlocking(target);
changed = changed || (current != target);
}
// 3) 智能翻倍mixin 接口
if (msg.opSmartDoubling != Op.NOOP && logic instanceof SmartDoublingHolder sd) {
if (msg.opSmartDoubling != Op.NOOP && logic instanceof ISmartDoublingHolder sd) {
boolean current = sd.eap$getSmartDoubling();
boolean target = computeTarget(current, msg.opSmartDoubling);
sd.eap$setSmartDoubling(target);

View File

@ -1,20 +1,20 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraft.world.InteractionResult;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.network.NetworkEvent;
import net.minecraftforge.network.NetworkHooks;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import com.extendedae_plus.client.ui.ProviderSelectScreen;
import net.minecraft.client.Minecraft;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import appeng.helpers.patternprovider.PatternContainer;
import appeng.menu.implementations.PatternAccessTermMenu;

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import appeng.menu.SlotSemantics;
import com.glodblock.github.extendedae.client.gui.GuiExPatternProvider;

View File

@ -1,11 +1,11 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
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.api.IAdvancedBlocking;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAccessor;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
@ -34,9 +34,9 @@ public class ToggleAdvancedBlockingC2SPacket {
var containerMenu = player.containerMenu;
if (containerMenu instanceof PatternProviderMenu menu) {
var accessor = (PatternProviderMenuAdvancedAccessor) menu;
var accessor = (PatternProviderMenuAccessor) menu;
var logic = accessor.eap$logic();
if (logic instanceof AdvancedBlockingHolder holder) {
if (logic instanceof IAdvancedBlocking holder) {
boolean current = holder.eap$getAdvancedBlocking();
boolean next = !current;
holder.eap$setAdvancedBlocking(next);
@ -48,7 +48,7 @@ public class ToggleAdvancedBlockingC2SPacket {
}else if (containerMenu instanceof AdvPatternProviderMenu menu){
var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu;
var logic = accessor.eap$logic();
if (logic instanceof AdvancedBlockingHolder holder) {
if (logic instanceof IAdvancedBlocking holder) {
boolean current = holder.eap$getAdvancedBlocking();
boolean next = !current;
holder.eap$setAdvancedBlocking(next);

View File

@ -1,9 +1,9 @@
package com.extendedae_plus.network;
package com.extendedae_plus.network.provider;
import appeng.menu.implementations.PatternProviderMenu;
import com.extendedae_plus.api.SmartDoublingHolder;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingHolder;
import com.extendedae_plus.mixin.advancedae.accessor.AdvPatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAdvancedAccessor;
import com.extendedae_plus.mixin.ae2.accessor.PatternProviderMenuAccessor;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.server.level.ServerPlayer;
import net.minecraftforge.network.NetworkEvent;
@ -31,9 +31,9 @@ public class ToggleSmartDoublingC2SPacket {
if (player == null) return;
var containerMenu = player.containerMenu;
if (containerMenu instanceof PatternProviderMenu menu) {
var accessor = (PatternProviderMenuAdvancedAccessor) menu;
var accessor = (PatternProviderMenuAccessor) menu;
var logic = accessor.eap$logic();
if (logic instanceof SmartDoublingHolder holder) {
if (logic instanceof ISmartDoublingHolder holder) {
boolean current = holder.eap$getSmartDoubling();
boolean next = !current;
holder.eap$setSmartDoubling(next);
@ -42,7 +42,7 @@ public class ToggleSmartDoublingC2SPacket {
}else if (containerMenu instanceof AdvPatternProviderMenu menu){
var accessor = (AdvPatternProviderMenuAdvancedAccessor) menu;
var logic = accessor.eap$logic();
if (logic instanceof SmartDoublingHolder holder) {
if (logic instanceof ISmartDoublingHolder holder) {
boolean current = holder.eap$getSmartDoubling();
boolean next = !current;
holder.eap$setSmartDoubling(next);

View File

@ -1,158 +0,0 @@
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<Pattern> compilePatterns(List<? extends String> raw) {
List<Pattern> 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<MultiplierEntry> parseMultiplierList(List<? extends String> raw) {
List<MultiplierEntry> 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<Pattern> cachedBlacklist = null;
private static volatile List<MultiplierEntry> cachedMultiplierEntries = null;
private static final Object CACHE_LOCK = new Object();
/**
* 获取已解析并缓存的黑名单线程安全懒加载
*/
public static List<Pattern> getCachedBlacklist(java.util.List<? extends String> source) {
if (cachedBlacklist == null) {
synchronized (CACHE_LOCK) {
if (cachedBlacklist == null) {
cachedBlacklist = compilePatterns(source);
}
}
}
return java.util.List.copyOf(cachedBlacklist);
}
/**
* 获取已解析并缓存的倍率列表线程安全懒加载
*/
public static List<MultiplierEntry> getCachedMultiplierEntries(java.util.List<? extends String> 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;
}
}
}

View File

@ -0,0 +1,41 @@
package com.extendedae_plus.util;
import appeng.api.config.Actionable;
import appeng.api.networking.energy.IEnergyService;
import appeng.api.networking.security.IActionSource;
import appeng.api.storage.MEStorage;
import appeng.api.storage.StorageHelper;
import com.glodblock.github.appflux.common.me.key.FluxKey;
import com.glodblock.github.appflux.common.me.key.type.EnergyType;
public class FluxEnergyHelper {
/**
* 尝试从 ME 存储提取 FE 能量
* @param energyService AE2 能量服务
* @param storage ME 存储
* @param feRequired 所需 FE
* @param source 操作来源
* @return 提取的 FE
*/
public static long extractFE(
IEnergyService energyService,
MEStorage storage,
long feRequired,
IActionSource source
) {
FluxKey feKey = FluxKey.of(EnergyType.FE);
// 模拟提取 FE
long feExtracted = StorageHelper.poweredExtraction(
energyService, storage, feKey, feRequired, source, Actionable.SIMULATE
);
// 执行实际提取
if (feExtracted >= feRequired) {
return StorageHelper.poweredExtraction(
energyService, storage, feKey, feRequired, source, Actionable.MODULATE
);
}
return 0;
}
}

View File

@ -1,127 +0,0 @@
package com.extendedae_plus.util;
import appeng.client.gui.implementations.PatternProviderScreen;
import appeng.helpers.patternprovider.PatternProviderLogic;
import appeng.menu.implementations.PatternProviderMenu;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.screens.Screen;
/**
* 样板供应器UI辅助工具类
* 用于在样板供应器界面中获取PatternProviderLogic对象
*/
public class PatternProviderUIHelper {
/**
* 获取当前打开的样板供应器的PatternProviderLogic
*
* @return PatternProviderLogic对象如果当前没有打开样板供应器界面则返回null
*/
public static PatternProviderLogic getCurrentPatternProvider() {
Minecraft mc = Minecraft.getInstance();
Screen currentScreen = mc.screen;
if (currentScreen instanceof PatternProviderScreen patternScreen) {
PatternProviderMenu menu = (PatternProviderMenu) patternScreen.getMenu();
// 通过反射安全地访问protected字段
try {
var logicField = PatternProviderMenu.class.getDeclaredField("logic");
logicField.setAccessible(true);
return (PatternProviderLogic) logicField.get(menu);
} catch (Exception e) {
// 如果反射失败返回null
return null;
}
}
return null;
}
/**
* 检查当前是否打开了样板供应器界面
*
* @return 如果当前打开的是样板供应器界面则返回true
*/
public static boolean isPatternProviderScreenOpen() {
Minecraft mc = Minecraft.getInstance();
return mc.screen instanceof PatternProviderScreen;
}
/**
* 获取当前样板供应器界面的Screen对象
*
* @return PatternProviderScreen对象如果当前没有打开样板供应器界面则返回null
*/
public static PatternProviderScreen getCurrentPatternProviderScreen() {
Minecraft mc = Minecraft.getInstance();
Screen currentScreen = mc.screen;
if (currentScreen instanceof PatternProviderScreen patternScreen) {
return patternScreen;
}
return null;
}
/**
* 在当前样板供应器中执行样板数量倍增
*
* @param multiplier 倍数必须大于0
* @return 缩放操作结果如果当前没有打开样板供应器界面则返回null
*/
public static PatternProviderDataUtil.PatternScalingResult multiplyCurrentPatternAmounts(double multiplier) {
PatternProviderLogic patternProvider = getCurrentPatternProvider();
if (patternProvider == null) {
return null;
}
return PatternProviderDataUtil.multiplyPatternAmounts(patternProvider, multiplier);
}
/**
* ExtendedAE风格的样板复制倍增
* 提供更好的错误处理和恢复机制
*
* @param multiplier 倍数必须大于0
* @return 缩放操作结果如果当前没有打开样板供应器界面则返回null
*/
public static PatternProviderDataUtil.PatternScalingResult duplicateCurrentPatternAmountsExtendedAEStyle(double multiplier) {
PatternProviderLogic patternProvider = getCurrentPatternProvider();
if (patternProvider == null) {
return null;
}
return PatternProviderDataUtil.duplicatePatternAmountsExtendedAEStyle(patternProvider, multiplier);
}
/**
* 在当前样板供应器中执行样板数量倍除
*
* @param divisor 除数必须大于0
* @return 缩放操作结果如果当前没有打开样板供应器界面则返回null
*/
public static PatternProviderDataUtil.PatternScalingResult divideCurrentPatternAmounts(double divisor) {
PatternProviderLogic patternProvider = getCurrentPatternProvider();
if (patternProvider == null) {
return null;
}
return PatternProviderDataUtil.dividePatternAmounts(patternProvider, divisor);
}
/**
* 预览当前样板供应器的缩放效果
*
* @param scaleFactor 缩放因子
* @return 预览结果列表如果当前没有打开样板供应器界面则返回空列表
*/
public static java.util.List<PatternProviderDataUtil.PatternScalingPreview> previewCurrentPatternScaling(double scaleFactor) {
PatternProviderLogic patternProvider = getCurrentPatternProvider();
if (patternProvider == null) {
return new java.util.ArrayList<>();
}
return PatternProviderDataUtil.previewPatternScaling(patternProvider, scaleFactor);
}
}

View File

@ -1,161 +0,0 @@
package com.extendedae_plus.util;
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem;
import com.extendedae_plus.config.ModConfig;
/**
* 用于计算实体加速器的能耗与加速倍率的工具类
*/
public final class PowerUtils {
private PowerUtils() {}
// ---- 重构后的 API ----
/**
* card multipliers按插槽序计算乘积并应用 cap 规则 capForHighestMultiplier
* @param multipliers iterable of per-card multipliers
* @param maxCards 最多计入的卡数
* @return cap 约束后的乘积
*/
public static long computeProductWithCap(Iterable<Integer> 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);
}
/**
* 根据最高单卡 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<Integer> 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<net.minecraft.world.item.ItemStack> stacks, int maxCards) {
java.util.List<Integer> 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 = ModConfig.INSTANCE.entityTickerCost;
// 计算以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;
if (speedCardCount <= 6) return Math.pow(2.0, 2.0 * speedCardCount);
return Math.pow(2.0, 3.0 * speedCardCount);
}
public static double getRawPower(int speedCardCount) {
double base = ModConfig.INSTANCE.entityTickerCost;
return base * getGrowthFactor(speedCardCount);
}
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));
}
public static double getFinalPower(int speedCardCount, int energyCardCount) {
double raw = getRawPower(speedCardCount);
double reduction = getReductionPercent(energyCardCount);
return raw * (1.0 - reduction) / 4.0;
}
/**
* 返回能源卡减免后剩余的功耗比率例如 1 张能源卡 -> 0.9
* @param energyCardCount 能源卡数量
* @return 剩余功耗比率
*/
public static double getRemainingRatio(int energyCardCount) {
return 1.0 - getReductionPercent(energyCardCount);
}
/**
* 将剩余功耗比率格式化为百分比字符串例如 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);
}
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.command;
package com.extendedae_plus.util.command;
import com.extendedae_plus.ExtendedAEPlus;
import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem;

View File

@ -0,0 +1,220 @@
package com.extendedae_plus.util.entitySpeed;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import static com.extendedae_plus.util.ExtendedAELogger.LOGGER;
/**
* 配置解析工具类用于解析黑名单与倍率配置的字符串
*/
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 语法'*' '?'以及完整的正则表达式
*/
public static Pattern compilePattern(String raw) {
if (raw == null || raw.trim().isEmpty()) {
LOGGER.warn("Invalid pattern: {}", raw);
throw new IllegalArgumentException("Pattern is null or empty");
}
raw = raw.trim();
// Try regex first if it contains regex metacharacters
if (raw.contains(".*") || raw.matches(".*[\\[\\(\\+\\{\\\\].*")) {
try {
return Pattern.compile("^" + raw + "$");
} catch (PatternSyntaxException e) {
LOGGER.warn("Failed to compile regex pattern '{}': {}", raw, e.getMessage());
// Fallback to glob
}
}
// Convert glob to regex
if (raw.contains("*") || raw.contains("?")) {
StringBuilder sb = new StringBuilder("^");
for (char c : raw.toCharArray()) {
switch (c) {
case '*': sb.append(".*"); break;
case '?': sb.append('.'); break;
default:
if (".\\+[]{}()^$|".indexOf(c) >= 0) {
sb.append('\\');
}
sb.append(c);
}
}
sb.append('$');
return Pattern.compile(sb.toString());
}
// Literal match
return Pattern.compile("^" + Pattern.quote(raw) + "$");
}
/**
* 解析倍率条目 'modid:block 2x'
*/
public static MultiplierEntry parseMultiplierEntry(String entry) {
if (entry == null || entry.trim().isEmpty()) return null;
String[] parts = entry.trim().split("\\s+");
if (parts.length < 2) {
LOGGER.warn("Invalid multiplier entry: {}", entry);
return null;
}
String key = parts[0];
String val = parts[1].toLowerCase();
if (val.endsWith("x")) val = val.substring(0, val.length() - 1);
double multiplier;
try {
multiplier = Double.parseDouble(val);
} catch (NumberFormatException e) {
LOGGER.warn("Invalid multiplier value in '{}': {}", entry, val);
return null;
}
try {
Pattern pattern = compilePattern(key);
return new MultiplierEntry(pattern, multiplier);
} catch (IllegalArgumentException e) {
LOGGER.warn("Failed to compile pattern in '{}': {}", entry, e.getMessage());
return null;
}
}
/**
* 检查方块是否在黑名单中
*/
public static boolean isBlockBlacklisted(String blockId, List<? extends String> blacklist) {
if (blockId == null) return false;
return getCachedBlacklist(blacklist).stream().anyMatch(p -> p.matcher(blockId).matches());
}
/**
* 获取方块的倍率
*/
public static double getMultiplierForBlock(String blockId, List<? extends String> multipliers) {
if (blockId == null) return 1.0;
double maxMultiplier = 1.0;
for (MultiplierEntry me : getCachedMultiplierEntries(multipliers)) {
if (me.pattern.matcher(blockId).matches()) {
maxMultiplier = Math.max(maxMultiplier, me.multiplier);
}
}
return maxMultiplier;
}
public static List<Pattern> compilePatterns(List<? extends String> raw) {
List<Pattern> out = new ArrayList<>();
if (raw == null) return out;
for (String s : raw) {
if (s == null || s.trim().isEmpty()) continue;
try {
out.add(compilePattern(s));
} catch (IllegalArgumentException e) {
LOGGER.warn("Failed to compile pattern '{}': {}", s, e.getMessage());
}
}
return out;
}
public static List<MultiplierEntry> parseMultiplierList(List<? extends String> raw) {
List<MultiplierEntry> 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<Pattern> cachedBlacklist = null;
private static volatile List<MultiplierEntry> cachedMultiplierEntries = null;
private static volatile List<String> cachedBlacklistSourceSnapshot = null;
private static volatile List<String> cachedMultiplierSourceSnapshot = null;
private static final Object CACHE_LOCK = new Object();
/**
* 获取已解析并缓存的黑名单线程安全懒加载
*/
public static List<Pattern> getCachedBlacklist(List<? extends String> source) {
List<String> normalized = normalizeSource(source);
if (cachedBlacklist != null && listEquals(cachedBlacklistSourceSnapshot, normalized)) {
return Collections.unmodifiableList(cachedBlacklist);
}
synchronized (CACHE_LOCK) {
if (cachedBlacklist == null || !listEquals(cachedBlacklistSourceSnapshot, normalized)) {
cachedBlacklist = compilePatterns(normalized);
cachedBlacklistSourceSnapshot = normalized.isEmpty() ? Collections.emptyList() : new ArrayList<>(normalized);
}
return Collections.unmodifiableList(cachedBlacklist);
}
}
/**
* 获取已解析并缓存的倍率列表线程安全懒加载
*/
public static List<MultiplierEntry> getCachedMultiplierEntries(List<? extends String> source) {
List<String> normalized = normalizeSource(source);
if (cachedMultiplierEntries != null && listEquals(cachedMultiplierSourceSnapshot, normalized)) {
return Collections.unmodifiableList(cachedMultiplierEntries);
}
synchronized (CACHE_LOCK) {
if (cachedMultiplierEntries == null || !listEquals(cachedMultiplierSourceSnapshot, normalized)) {
cachedMultiplierEntries = parseMultiplierList(normalized);
cachedMultiplierSourceSnapshot = normalized.isEmpty() ? Collections.emptyList() : new ArrayList<>(normalized);
}
return Collections.unmodifiableList(cachedMultiplierEntries);
}
}
// Normalize the incoming source list: trim entries, drop blanks, keep stable ordering
private static List<String> normalizeSource(java.util.List<? extends String> source) {
List<String> out = new ArrayList<>();
if (source == null) return out;
for (String s : source) {
if (s == null) continue;
String t = s.trim();
if (t.isEmpty()) continue;
out.add(t);
}
return out;
}
// Null-safe equality for two lists of strings. Uses size + element equals.
private static boolean listEquals(List<String> a, List<String> b) {
if (a == b) return true;
if (a == null || b == null) return false;
if (a.size() != b.size()) return false;
for (int i = 0; i < a.size(); i++) {
if (!a.get(i).equals(b.get(i))) return false;
}
return true;
}
/**
* 清空缓存下一次获取时将重新从提供的源解析或调用方可以重新调用 getter
*/
public static void reload() {
synchronized (CACHE_LOCK) {
cachedBlacklist = null;
cachedMultiplierEntries = null;
cachedBlacklistSourceSnapshot = null;
cachedMultiplierSourceSnapshot = null;
}
}
}

View File

@ -0,0 +1,98 @@
package com.extendedae_plus.util.entitySpeed;
import appeng.api.upgrades.IUpgradeInventory;
import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem;
import com.extendedae_plus.config.ModConfig;
import net.minecraft.world.item.ItemStack;
import java.util.ArrayList;
import java.util.List;
/**
* 用于计算实体加速器的能耗与加速倍率的工具类
*/
public final class PowerUtils {
private PowerUtils() {}
/**
* 计算加速卡的乘积并应用上限
* @param upgrades 升级槽位
* @param maxCards 最大计入的卡数
* @return 被上限约束后的乘积
*/
public static long computeProductWithCap(IUpgradeInventory upgrades, int maxCards) {
List<Integer> multipliers = new ArrayList<>();
int considered = 0;
for (ItemStack stack : upgrades) {
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++) {
multipliers.add(multVal);
considered++;
}
}
}
long product = 1L;
int highest = 1;
for (Integer m : multipliers) {
if (m == null || m <= 0) continue;
product *= m;
highest = Math.max(highest, m);
}
return Math.min(product, capForHighestMultiplier(highest));
}
/**
* 根据最高单卡倍率返回上限值
*/
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;
}
/**
* 计算最终能耗
* @param product 加速卡乘积
* @param energyCardCount 能量卡数量
* @return 最终能耗值
*/
public static double computeFinalPowerForProduct(long product, int energyCardCount) {
if (product <= 1L) return 0.0;
double base = ModConfig.INSTANCE.entityTickerCost;
double log2 = Math.log(product) / Math.log(2.0);
double raw;
if (product == 2L) {
raw = base * 4;
} else if (product <= 256L) {
raw = base * Math.pow(2.0, 1.5 * log2) * 2;
} else {
raw = base * Math.pow(2.0, 2.5 * log2);
}
return raw * getRemainingRatio(energyCardCount) / 8.0;
}
/**
* 计算能量卡减免后的剩余功耗比率
*/
public static double getRemainingRatio(int energyCardCount) {
if (energyCardCount <= 0) return 1.0;
if (energyCardCount == 1) return 0.9;
if (energyCardCount >= 8) return 0.5;
return 1.0 - 0.5 * (1.0 - Math.pow(0.7, energyCardCount));
}
/**
* 将剩余功耗比率格式化为百分比字符串
*/
public static String formatPercentage(double ratio) {
double pct = ratio * 100.0;
return Math.abs(pct - Math.round(pct)) < 1e-9 ?
String.format("%d%%", Math.round(pct)) :
String.format("%.2f%%", pct);
}
}

View File

@ -1,11 +1,11 @@
package com.extendedae_plus.util;
package com.extendedae_plus.util.smartDoubling;
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.ae.api.crafting.ScaledProcessingPattern;
import com.extendedae_plus.api.smartDoubling.ISmartDoublingAwarePattern;
import com.extendedae_plus.config.ModConfig;
import com.extendedae_plus.content.ScaledProcessingPattern;
public final class PatternScaler {
private PatternScaler() {
@ -16,7 +16,7 @@ public final class PatternScaler {
if (target == null) throw new IllegalArgumentException("target");
// 双保险若样板标记为不允许缩放直接放弃缩放返回 null 表示调用方应保持原样板
if (base instanceof SmartDoublingAwarePattern aware && !aware.eap$allowScaling()) {
if (base instanceof ISmartDoublingAwarePattern aware && !aware.eap$allowScaling()) {
return null;
}

View File

@ -1,4 +1,4 @@
package com.extendedae_plus.util;
package com.extendedae_plus.util.smartDoubling;
import java.util.ArrayDeque;
import java.util.Deque;

Some files were not shown because too many files have changed in this diff Show More