diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index 0531741..270131d 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -5,9 +5,13 @@ import appeng.menu.implementations.UpgradeableMenu; import appeng.menu.slot.OptionalFakeSlot; import com.extendedae_plus.ae.parts.EntitySpeedTickerPart; import com.extendedae_plus.ae.screen.EntitySpeedTickerScreen; +import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.ModMenuTypes; +import com.extendedae_plus.util.ConfigParsingUtils; import net.minecraft.client.Minecraft; import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraftforge.registries.ForgeRegistries; // 实体加速器菜单,负责与客户端界面同步数据 public class EntitySpeedTickerMenu extends UpgradeableMenu { @@ -15,6 +19,8 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu * 该部件可以加速目标方块实体的 tick 速率,消耗 AE 网络能量,并支持加速卡升级

@@ -165,12 +172,19 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka return; } -// String id = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString(); - // 获取方块实体的位置 BlockPos pos = blockEntity.getBlockPos(); if (blockEntity.getLevel() == null) return; + // 检查黑名单(支持通配符/正则) + String blockId = Objects.requireNonNull(ForgeRegistries.BLOCKS.getKey(blockEntity.getBlockState().getBlock())).toString(); + + // 使用工具类的缓存接口(工具类内部负责懒加载/线程安全) + List compiledBlacklist = ConfigParsingUtils.getCachedBlacklist(ModConfigs.EntitySpeedTickerBlackList.get()); + for (Pattern p : compiledBlacklist) { + if (p.matcher(blockId).matches()) return; + } + // 获取该方块实体的 Ticker @SuppressWarnings("unchecked") BlockEntityTicker blockEntityTicker = this.getLevel() @@ -191,6 +205,15 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka // 使用工具类统一计算增长因子与原始功耗,并从网络中抽取对应能量 double requiredPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); + double multiplier = 1.0; + for (ConfigParsingUtils.MultiplierEntry me : ConfigParsingUtils.getCachedMultiplierEntries(ModConfigs.EntitySpeedTickerMultipliers.get())) { + if (me.pattern.matcher(blockId).matches()) { + multiplier = Math.max(multiplier, me.multiplier); + } + } + + requiredPower *= multiplier; + // 先模拟提取以检查网络中是否有足够能量,再真正抽取 double simulated = getMainNode().getGrid().getEnergyService() .extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG); diff --git a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java index eb37978..3bbe7e1 100644 --- a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java +++ b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java @@ -27,6 +27,7 @@ public class EntitySpeedTickerScreen extends Up private void textData() { int speedCardCount = getMenu().speedCardCount; int energyCardCount = getMenu().energyCardCount; + double multiplier = getMenu().multiplier; double finalPower = PowerUtils.getFinalPower(speedCardCount, energyCardCount); int speed = PowerUtils.getSpeedMultiplier(speedCardCount); @@ -35,5 +36,6 @@ public class EntitySpeedTickerScreen extends Up setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", speed)); setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", PowerUtils.formatPower(finalPower))); setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); + setTextContent("multiplier", Component.translatable("screen.extendedae_plus.entity_speed_ticker.multiplier", String.format("%.2fx", multiplier))); } } \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/config/ModConfigs.java b/src/main/java/com/extendedae_plus/config/ModConfigs.java index a746b53..623ab8d 100644 --- a/src/main/java/com/extendedae_plus/config/ModConfigs.java +++ b/src/main/java/com/extendedae_plus/config/ModConfigs.java @@ -12,7 +12,9 @@ public final class ModConfigs { public static final ForgeConfigSpec.BooleanValue PATTERN_TERMINAL_SHOW_SLOTS_DEFAULT; public static final ForgeConfigSpec.IntValue SMART_SCALING_MAX_MULTIPLIER; public static final ForgeConfigSpec.IntValue SMART_SCALING_MIN_BENEFIT_FACTOR; - public static final ForgeConfigSpec.IntValue EntityTickerCost; + public static final ForgeConfigSpec.IntValue EntitySpeedTickerCost; + public static final ForgeConfigSpec.ConfigValue> EntitySpeedTickerBlackList; + public static final ForgeConfigSpec.ConfigValue> EntitySpeedTickerMultipliers; static { @@ -81,10 +83,26 @@ public final class ModConfigs { .define("patternTerminalShowSlotsDefault", true); - EntityTickerCost = builder + builder.push("EntitySpeedTicker"); + EntitySpeedTickerCost = builder .comment("实体加速器的能量消耗基础值") .defineInRange("EntityTickerCost", 512, 0, Integer.MAX_VALUE); + EntitySpeedTickerBlackList = builder + .comment( + "实体加速器黑名单:匹配的方块将不会被加速。支持通配符/正则(例如:minecraft:*)", + "格式:全名或通配符/正则字符串,例如 'minecraft:chest'、'minecraft:*'、'modid:.*_fluid'" + ) + .defineList("EntityTickerBlackList", java.util.List.of(), o -> o instanceof String); + + EntitySpeedTickerMultipliers = builder + .comment( + "额外消耗倍率配置:为某些方块设置额外能量倍率,格式 'modid:blockid multiplier',例如 'minecraft:chest 2x'", + "支持通配符/正则匹配(例如 'minecraft:* 2x' 会对整个命名空间生效)。" + ) + .defineList("EntityTickerMultipliers", java.util.List.of(), o -> o instanceof String); + builder.pop(); + builder.pop(); COMMON_SPEC = builder.build(); } diff --git a/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java b/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java new file mode 100644 index 0000000..b9377a5 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java @@ -0,0 +1,158 @@ +package com.extendedae_plus.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * 配置解析工具类:用于解析黑名单与倍率配置的字符串 + */ +public final class ConfigParsingUtils { + private ConfigParsingUtils() {} + + public static final class MultiplierEntry { + public final Pattern pattern; + public final double multiplier; + + public MultiplierEntry(Pattern pattern, double multiplier) { + this.pattern = pattern; + this.multiplier = multiplier; + } + } + + /** + * 编译用户提供的匹配串。支持简单的 glob 语法('*' 和 '?')以及完整的正则表达式。 + * 规则: + * - 如果字符串包含 ".*" 或其他正则元字符,优先尝试按正则编译(若失败则回退到 glob 转换)。 + * - 否则若包含 '*' 或 '?',将按 glob 语法转换为正则。 + * - 否则按字面量匹配处理。 + */ + public static Pattern compilePattern(String raw) { + if (raw == null) throw new IllegalArgumentException("pattern is null"); + raw = raw.trim(); + if (raw.isEmpty()) throw new IllegalArgumentException("pattern is empty"); + + // If it looks like regex (contains '.*' or regex metachar), try regex first + if (raw.contains(".*") || raw.matches(".*[\\[\\(\\+\\{\\\\].*")) { + try { + return Pattern.compile("^" + raw + "$"); + } catch (PatternSyntaxException ignored) { + // fallback to glob below + } + } + + // If contains glob chars, convert to regex + if (raw.contains("*") || raw.contains("?")) { + StringBuilder sb = new StringBuilder(); + sb.append('^'); + for (char c : raw.toCharArray()) { + switch (c) { + case '*': sb.append(".*"); break; + case '?': sb.append('.'); break; + default: + // escape regex special chars + if (".\\+[]{}()^$|".indexOf(c) >= 0) { + sb.append('\\'); + } + sb.append(c); + } + } + sb.append('$'); + return Pattern.compile(sb.toString()); + } + + // Otherwise treat as a literal (match exact) + return Pattern.compile("^" + Pattern.quote(raw) + "$"); + } + + /** + * Parse multiplier entries like 'modid:block 2x' into MultiplierEntry objects. + * Accepts values with optional trailing 'x' (case-insensitive). + */ + public static MultiplierEntry parseMultiplierEntry(String entry) { + if (entry == null) return null; + String[] parts = entry.trim().split("\\s+"); + if (parts.length < 2) return null; + String key = parts[0]; + String val = parts[1].toLowerCase(); + if (val.endsWith("x")) val = val.substring(0, val.length() - 1); + double m; + try { + m = Double.parseDouble(val); + } catch (NumberFormatException ex) { + return null; + } + try { + Pattern p = compilePattern(key); + return new MultiplierEntry(p, m); + } catch (IllegalArgumentException e) { + return null; + } + } + + public static List compilePatterns(List raw) { + List out = new ArrayList<>(); + if (raw == null) return out; + for (String s : raw) { + if (s == null || s.isBlank()) continue; + try { out.add(compilePattern(s)); } catch (IllegalArgumentException ignored) {} + } + return out; + } + + public static List parseMultiplierList(List raw) { + List out = new ArrayList<>(); + if (raw == null) return out; + for (String s : raw) { + MultiplierEntry me = parseMultiplierEntry(s); + if (me != null) out.add(me); + } + return out; + } + + // ------------------ 全局缓存与接口 ------------------ + private static volatile List cachedBlacklist = null; + private static volatile List cachedMultiplierEntries = null; + private static final Object CACHE_LOCK = new Object(); + + /** + * 获取已解析并缓存的黑名单(线程安全、懒加载)。 + */ + public static List getCachedBlacklist(java.util.List source) { + if (cachedBlacklist == null) { + synchronized (CACHE_LOCK) { + if (cachedBlacklist == null) { + cachedBlacklist = compilePatterns(source); + } + } + } + return java.util.List.copyOf(cachedBlacklist); + } + + /** + * 获取已解析并缓存的倍率列表(线程安全、懒加载)。 + */ + public static List getCachedMultiplierEntries(java.util.List source) { + if (cachedMultiplierEntries == null) { + synchronized (CACHE_LOCK) { + if (cachedMultiplierEntries == null) { + cachedMultiplierEntries = parseMultiplierList(source); + } + } + } + return java.util.List.copyOf(cachedMultiplierEntries); + } + + /** + * 清空缓存,下一次获取时将重新从提供的源解析(或调用方可以重新调用 getter)。 + */ + public static void reload() { + synchronized (CACHE_LOCK) { + cachedBlacklist = null; + cachedMultiplierEntries = null; + } + } +} + + diff --git a/src/main/java/com/extendedae_plus/util/PowerUtils.java b/src/main/java/com/extendedae_plus/util/PowerUtils.java index ef42443..067af5c 100644 --- a/src/main/java/com/extendedae_plus/util/PowerUtils.java +++ b/src/main/java/com/extendedae_plus/util/PowerUtils.java @@ -37,7 +37,7 @@ public final class PowerUtils { * @return 原始能耗 */ public static double getRawPower(int speedCardCount) { - double base = ModConfigs.EntityTickerCost.get(); + double base = ModConfigs.EntitySpeedTickerCost.get(); return base * getGrowthFactor(speedCardCount); } diff --git a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json index acde6c9..64dfc30 100644 --- a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json +++ b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json @@ -44,6 +44,14 @@ }, "align": "CENTER" } + , + "multiplier": { + "position": { + "top": 90, + "left": 88 + }, + "align": "CENTER" + } }, "widgets": { "toolbox": { diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 93331f1..b112fd2 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -3,6 +3,7 @@ "screen.extendedae_plus.entity_speed_ticker.energy": "Energy Usage: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power ratio: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "Current speed multiplier: %d", + "screen.extendedae_plus.entity_speed_ticker.multiplier": "Extra consumption multiplier: %s", "gui.expatternprovider.toggle_slots": "Toggle Slots", "gui.expatternprovider.hide_slots": "Hide Slots", @@ -29,8 +30,7 @@ "config.jade.plugin_extendedae_plus.wt_network_usable": "Show Network Online State", "extendedae_plus.tooltip.frequency": "Frequency: %d", "extendedae_plus.tooltip.master_mode": "Mode: %s", - "extendedae_plus.tooltip.locked": "Locked: %s" - , + "extendedae_plus.tooltip.locked": "Locked: %s", "screen.extendedae_plus.title": "ExtendedAE Plus Config", "config.extendedae_plus.pageMultiplier": "Pattern Provider Page Multiplier", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 09eadc2..619b23f 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -33,6 +33,7 @@ "screen.extendedae_plus.entity_speed_ticker.energy": "能耗: %s FE/t", "screen.extendedae_plus.entity_speed_ticker.power_ratio": "功耗比例: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d", + "screen.extendedae_plus.entity_speed_ticker.multiplier": "额外消耗倍率: %s", "config.jade.plugin_extendedae_plus.wireless_transceiver_info": "无线收发器信息", "config.jade.plugin_extendedae_plus.wt_frequency": "显示频率",