From ca1ad2190a7ebed52493a079006c91ed0ba67cbe Mon Sep 17 00:00:00 2001 From: Aedial Date: Tue, 4 Aug 2026 01:27:57 +0200 Subject: [PATCH 1/4] Add upgrades picker for Storage Level Emitter --- CHANGELOG.md | 3 +- .../maintainer/MaintainerProbeHelper.java | 86 ++++++++- .../monitor/StorageMonitorProbeHelper.java | 165 ++++++++++++++++++ .../PowerToolsTheOneProbePlugin.java | 77 +++++++- .../waila/PowerToolsWailaModule.java | 100 ++++++++++- .../assets/ae2powertools/lang/en_us.lang | 6 + 6 files changed, 431 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/ae2powertools/features/monitor/StorageMonitorProbeHelper.java diff --git a/CHANGELOG.md b/CHANGELOG.md index ed39acb..691c1b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,8 +16,9 @@ The format is based on Keep a Changelog and this project adheres to Semantic Ver ## [1.6.7] - 2026-08-666 ### Added - Add AutoCrafter WAILA and The One Probe summary tooltips, including next-operation timing, error warnings, and active/full/disabled pattern counts. -- Add support for the Crafting and Fuzzy card to the Storage Level Emitter, bringing it to feature parity with the AE2 Level Emitter. There is not yet a way to insert the cards into the Emitter. +- Add support for the Crafting and Fuzzy card to the Storage Level Emitter, bringing it to feature parity with the AE2 Level Emitter, alongside a cards picker GUI to easily select the card to use. - Add AutoCrafter and Better Level Maintainer WAILA/The One Probe performance lines that report the block-side work time, including rolling last/average/max samples. +- Add Better Level Maintainer, Storage Level Emitter, and Level Monitor Alarm WAILA/The One Probe lines for maintainer queue status, emitter card/redstone mode, and per-player alarm registration. ### Fixed - Fix AutoCrafter crafting instantly when batch * speed (in ticks) goes above max int, which happens when batch is at max int / 20 at default speed. diff --git a/src/main/java/com/ae2powertools/features/maintainer/MaintainerProbeHelper.java b/src/main/java/com/ae2powertools/features/maintainer/MaintainerProbeHelper.java index 76b10a6..603a53b 100644 --- a/src/main/java/com/ae2powertools/features/maintainer/MaintainerProbeHelper.java +++ b/src/main/java/com/ae2powertools/features/maintainer/MaintainerProbeHelper.java @@ -10,10 +10,18 @@ */ public final class MaintainerProbeHelper { + public static final String STATUS_CPU_TOOLTIP_KEY = "tooltip.ae2powertools.maintainer.cpus"; + public static final String STATUS_RECIPE_TOOLTIP_KEY = "tooltip.ae2powertools.maintainer.recipes"; public static final String PERFORMANCE_NONE_TOOLTIP_KEY = "tooltip.ae2powertools.performance.none"; public static final String PERFORMANCE_SUMMARY_TOOLTIP_KEY = "tooltip.ae2powertools.performance.summary"; public static final String WAILA_HAS_VALID_TILE_KEY = "ae2powertoolsHasMaintainerProbeData"; + public static final String WAILA_ACTIVE_CPU_COUNT_KEY = "ae2powertoolsMaintainerActiveCpuCount"; + public static final String WAILA_TOTAL_CPU_COUNT_KEY = "ae2powertoolsMaintainerTotalCpuCount"; + public static final String WAILA_RUNNING_RECIPE_COUNT_KEY = "ae2powertoolsMaintainerRunningRecipeCount"; + public static final String WAILA_TOTAL_RECIPE_COUNT_KEY = "ae2powertoolsMaintainerTotalRecipeCount"; + public static final String WAILA_FAILED_RECIPE_COUNT_KEY = "ae2powertoolsMaintainerFailedRecipeCount"; + public static final String WAILA_POST_ERROR_RECIPE_COUNT_KEY = "ae2powertoolsMaintainerPostErrorRecipeCount"; public static final String WAILA_HAS_TIMING_SAMPLE_KEY = "ae2powertoolsHasMaintainerTimingSample"; public static final String WAILA_LAST_WORK_DURATION_NANOS_KEY = "ae2powertoolsMaintainerLastWorkDurationNanos"; public static final String WAILA_AVERAGE_WORK_DURATION_NANOS_KEY = "ae2powertoolsMaintainerAverageWorkDurationNanos"; @@ -30,6 +38,12 @@ public static ProbeData collectData(TileBetterLevelMaintainer maintainer) { return new ProbeData( true, + maintainer.getActiveCpuCount(), + maintainer.getTotalCpuCount(), + maintainer.getRunningRecipeCount(), + maintainer.getTotalRecipeCount(), + maintainer.getFailedRecipeCount(), + maintainer.getPostErrorRecipeCount(), maintainer.hasWorkTimingSamples(), maintainer.getLastWorkDurationNanos(), maintainer.getAverageWorkDurationNanos(), @@ -45,6 +59,12 @@ public static ProbeData readWailaData(NBTTagCompound tag) { return new ProbeData( true, + tag.getInteger(WAILA_ACTIVE_CPU_COUNT_KEY), + tag.getInteger(WAILA_TOTAL_CPU_COUNT_KEY), + tag.getInteger(WAILA_RUNNING_RECIPE_COUNT_KEY), + tag.getInteger(WAILA_TOTAL_RECIPE_COUNT_KEY), + tag.getInteger(WAILA_FAILED_RECIPE_COUNT_KEY), + tag.getInteger(WAILA_POST_ERROR_RECIPE_COUNT_KEY), tag.getBoolean(WAILA_HAS_TIMING_SAMPLE_KEY), tag.getLong(WAILA_LAST_WORK_DURATION_NANOS_KEY), tag.getLong(WAILA_AVERAGE_WORK_DURATION_NANOS_KEY), @@ -57,6 +77,12 @@ public static void writeWailaData(TileBetterLevelMaintainer maintainer, NBTTagCo ProbeData data = collectData(maintainer); tag.setBoolean(WAILA_HAS_VALID_TILE_KEY, data.isValid()); + tag.setInteger(WAILA_ACTIVE_CPU_COUNT_KEY, data.getActiveCpuCount()); + tag.setInteger(WAILA_TOTAL_CPU_COUNT_KEY, data.getTotalCpuCount()); + tag.setInteger(WAILA_RUNNING_RECIPE_COUNT_KEY, data.getRunningRecipeCount()); + tag.setInteger(WAILA_TOTAL_RECIPE_COUNT_KEY, data.getTotalRecipeCount()); + tag.setInteger(WAILA_FAILED_RECIPE_COUNT_KEY, data.getFailedRecipeCount()); + tag.setInteger(WAILA_POST_ERROR_RECIPE_COUNT_KEY, data.getPostErrorRecipeCount()); tag.setBoolean(WAILA_HAS_TIMING_SAMPLE_KEY, data.hasTimingSample()); tag.setLong(WAILA_LAST_WORK_DURATION_NANOS_KEY, data.getLastWorkDurationNanos()); tag.setLong(WAILA_AVERAGE_WORK_DURATION_NANOS_KEY, data.getAverageWorkDurationNanos()); @@ -66,17 +92,35 @@ public static void writeWailaData(TileBetterLevelMaintainer maintainer, NBTTagCo public static final class ProbeData { private final boolean valid; + private final int activeCpuCount; + private final int totalCpuCount; + private final int runningRecipeCount; + private final int totalRecipeCount; + private final int failedRecipeCount; + private final int postErrorRecipeCount; private final boolean timingSample; private final long lastWorkDurationNanos; private final long averageWorkDurationNanos; private final long maxWorkDurationNanos; private ProbeData(boolean valid, + int activeCpuCount, + int totalCpuCount, + int runningRecipeCount, + int totalRecipeCount, + int failedRecipeCount, + int postErrorRecipeCount, boolean timingSample, long lastWorkDurationNanos, long averageWorkDurationNanos, long maxWorkDurationNanos) { this.valid = valid; + this.activeCpuCount = Math.max(0, activeCpuCount); + this.totalCpuCount = Math.max(0, totalCpuCount); + this.runningRecipeCount = Math.max(0, runningRecipeCount); + this.totalRecipeCount = Math.max(0, totalRecipeCount); + this.failedRecipeCount = Math.max(0, failedRecipeCount); + this.postErrorRecipeCount = Math.max(0, postErrorRecipeCount); this.timingSample = timingSample; this.lastWorkDurationNanos = Math.max(0L, lastWorkDurationNanos); this.averageWorkDurationNanos = Math.max(0L, averageWorkDurationNanos); @@ -84,13 +128,37 @@ private ProbeData(boolean valid, } public static ProbeData invalid() { - return new ProbeData(false, false, 0L, 0L, 0L); + return new ProbeData(false, 0, 0, 0, 0, 0, 0, false, 0L, 0L, 0L); } public boolean isValid() { return valid; } + public int getActiveCpuCount() { + return activeCpuCount; + } + + public int getTotalCpuCount() { + return totalCpuCount; + } + + public int getRunningRecipeCount() { + return runningRecipeCount; + } + + public int getTotalRecipeCount() { + return totalRecipeCount; + } + + public int getFailedRecipeCount() { + return failedRecipeCount; + } + + public int getPostErrorRecipeCount() { + return postErrorRecipeCount; + } + public boolean hasTimingSample() { return timingSample; } @@ -113,6 +181,22 @@ public String getTimingKey() { return PERFORMANCE_SUMMARY_TOOLTIP_KEY; } + public String[] getCpuStatusArgs() { + return new String[] { + Integer.toString(activeCpuCount), + Integer.toString(totalCpuCount) + }; + } + + public String[] getRecipeStatusArgs() { + return new String[] { + Integer.toString(runningRecipeCount), + Integer.toString(totalRecipeCount), + Integer.toString(failedRecipeCount), + Integer.toString(postErrorRecipeCount) + }; + } + public String[] getTimingArgs() { if (!timingSample) return new String[0]; diff --git a/src/main/java/com/ae2powertools/features/monitor/StorageMonitorProbeHelper.java b/src/main/java/com/ae2powertools/features/monitor/StorageMonitorProbeHelper.java new file mode 100644 index 0000000..af59b0b --- /dev/null +++ b/src/main/java/com/ae2powertools/features/monitor/StorageMonitorProbeHelper.java @@ -0,0 +1,165 @@ +package com.ae2powertools.features.monitor; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.nbt.NBTTagCompound; + +import com.ae2powertools.features.monitor.alarm.TileLevelMonitorAlarm; +import com.ae2powertools.features.monitor.emitter.EmitterRedstonePower; +import com.ae2powertools.features.monitor.emitter.IEmitterCardHost; + + +/** + * Shared tooltip helpers for Storage Level Emitter and Level Monitor Alarm probe integrations. + */ +public final class StorageMonitorProbeHelper { + + public static final String EMITTER_FUZZY_CARD_TOOLTIP_KEY = "tooltip.ae2powertools.storage_emitter.card.fuzzy"; + public static final String EMITTER_CRAFTING_CARD_TOOLTIP_KEY = "tooltip.ae2powertools.storage_emitter.card.crafting"; + public static final String EMITTER_REDSTONE_WEAK_TOOLTIP_KEY = "tooltip.ae2powertools.storage_emitter.redstone.weak"; + public static final String EMITTER_REDSTONE_STRONG_TOOLTIP_KEY = "tooltip.ae2powertools.storage_emitter.redstone.strong"; + + public static final String WAILA_HAS_EMITTER_DATA_KEY = "ae2powertoolsHasEmitterProbeData"; + public static final String WAILA_EMITTER_HAS_FUZZY_CARD_KEY = "ae2powertoolsEmitterHasFuzzyCard"; + public static final String WAILA_EMITTER_HAS_CRAFTING_CARD_KEY = "ae2powertoolsEmitterHasCraftingCard"; + public static final String WAILA_EMITTER_REDSTONE_POWER_KEY = "ae2powertoolsEmitterRedstonePower"; + + public static final String WAILA_HAS_ALARM_DATA_KEY = "ae2powertoolsHasAlarmProbeData"; + public static final String WAILA_ALARM_PLAYER_REGISTERED_KEY = "ae2powertoolsAlarmPlayerRegistered"; + + private StorageMonitorProbeHelper() {} + + public static EmitterProbeData collectEmitterData(IEmitterCardHost emitter) { + if (emitter == null) return EmitterProbeData.invalid(); + + return new EmitterProbeData( + true, + emitter.hasFuzzyCard(), + emitter.hasCraftingCard(), + emitter.getRedstonePower()); + } + + public static boolean shouldRenderEmitter(NBTTagCompound tag) { + return tag != null && tag.getBoolean(WAILA_HAS_EMITTER_DATA_KEY); + } + + public static EmitterProbeData readEmitterWailaData(NBTTagCompound tag) { + if (!shouldRenderEmitter(tag)) return EmitterProbeData.invalid(); + + return new EmitterProbeData( + true, + tag.getBoolean(WAILA_EMITTER_HAS_FUZZY_CARD_KEY), + tag.getBoolean(WAILA_EMITTER_HAS_CRAFTING_CARD_KEY), + EmitterRedstonePower.fromId(tag.getInteger(WAILA_EMITTER_REDSTONE_POWER_KEY))); + } + + public static void writeEmitterWailaData(IEmitterCardHost emitter, NBTTagCompound tag) { + if (emitter == null || tag == null) return; + + EmitterProbeData data = collectEmitterData(emitter); + + tag.setBoolean(WAILA_HAS_EMITTER_DATA_KEY, data.isValid()); + tag.setBoolean(WAILA_EMITTER_HAS_FUZZY_CARD_KEY, data.hasFuzzyCard()); + tag.setBoolean(WAILA_EMITTER_HAS_CRAFTING_CARD_KEY, data.hasCraftingCard()); + tag.setInteger(WAILA_EMITTER_REDSTONE_POWER_KEY, data.getRedstonePower().getId()); + } + + public static AlarmProbeData collectAlarmData(TileLevelMonitorAlarm alarm, EntityPlayer player) { + if (alarm == null) return AlarmProbeData.invalid(); + + return new AlarmProbeData(true, alarm.isPlayerRegistered(player)); + } + + public static boolean shouldRenderAlarm(NBTTagCompound tag) { + return tag != null && tag.getBoolean(WAILA_HAS_ALARM_DATA_KEY); + } + + public static AlarmProbeData readAlarmWailaData(NBTTagCompound tag) { + if (!shouldRenderAlarm(tag)) return AlarmProbeData.invalid(); + + return new AlarmProbeData(true, tag.getBoolean(WAILA_ALARM_PLAYER_REGISTERED_KEY)); + } + + public static void writeAlarmWailaData(TileLevelMonitorAlarm alarm, EntityPlayer player, NBTTagCompound tag) { + if (alarm == null || tag == null) return; + + AlarmProbeData data = collectAlarmData(alarm, player); + + tag.setBoolean(WAILA_HAS_ALARM_DATA_KEY, data.isValid()); + tag.setBoolean(WAILA_ALARM_PLAYER_REGISTERED_KEY, data.isRegistered()); + } + + public static final class EmitterProbeData { + + private final boolean valid; + private final boolean fuzzyCard; + private final boolean craftingCard; + private final EmitterRedstonePower redstonePower; + + private EmitterProbeData(boolean valid, + boolean fuzzyCard, + boolean craftingCard, + EmitterRedstonePower redstonePower) { + this.valid = valid; + this.fuzzyCard = fuzzyCard; + this.craftingCard = craftingCard; + this.redstonePower = redstonePower == null ? EmitterRedstonePower.WEAK : redstonePower; + } + + public static EmitterProbeData invalid() { + return new EmitterProbeData(false, false, false, EmitterRedstonePower.WEAK); + } + + public boolean isValid() { + return valid; + } + + public boolean hasFuzzyCard() { + return fuzzyCard; + } + + public boolean hasCraftingCard() { + return craftingCard; + } + + public EmitterRedstonePower getRedstonePower() { + return redstonePower; + } + + public String getRedstoneModeKey() { + if (redstonePower == EmitterRedstonePower.STRONG) { + return EMITTER_REDSTONE_STRONG_TOOLTIP_KEY; + } + + return EMITTER_REDSTONE_WEAK_TOOLTIP_KEY; + } + } + + public static final class AlarmProbeData { + + private final boolean valid; + private final boolean registered; + + private AlarmProbeData(boolean valid, boolean registered) { + this.valid = valid; + this.registered = registered; + } + + public static AlarmProbeData invalid() { + return new AlarmProbeData(false, false); + } + + public boolean isValid() { + return valid; + } + + public boolean isRegistered() { + return registered; + } + + public String getRegistrationKey() { + return registered + ? "gui.ae2powertools.level_monitor_alarm.registration.registered" + : "gui.ae2powertools.level_monitor_alarm.registration.unregistered"; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ae2powertools/integration/theoneprobe/PowerToolsTheOneProbePlugin.java b/src/main/java/com/ae2powertools/integration/theoneprobe/PowerToolsTheOneProbePlugin.java index 50d3cf1..58af779 100644 --- a/src/main/java/com/ae2powertools/integration/theoneprobe/PowerToolsTheOneProbePlugin.java +++ b/src/main/java/com/ae2powertools/integration/theoneprobe/PowerToolsTheOneProbePlugin.java @@ -1,5 +1,6 @@ package com.ae2powertools.integration.theoneprobe; +import java.util.Optional; import java.util.function.Function; import net.minecraft.block.state.IBlockState; @@ -8,6 +9,9 @@ import net.minecraft.world.World; import net.minecraftforge.fml.common.event.FMLInterModComms; +import appeng.api.parts.IPart; +import appeng.integration.modules.theoneprobe.part.PartAccessor; + import mcjty.theoneprobe.api.IProbeHitData; import mcjty.theoneprobe.api.IProbeInfo; import mcjty.theoneprobe.api.IProbeInfoProvider; @@ -19,10 +23,17 @@ import com.ae2powertools.features.crafter.TileAutoCrafter; import com.ae2powertools.features.maintainer.MaintainerProbeHelper; import com.ae2powertools.features.maintainer.TileBetterLevelMaintainer; +import com.ae2powertools.features.monitor.StorageMonitorProbeHelper; +import com.ae2powertools.features.monitor.StorageMonitorProbeHelper.AlarmProbeData; +import com.ae2powertools.features.monitor.StorageMonitorProbeHelper.EmitterProbeData; +import com.ae2powertools.features.monitor.alarm.TileLevelMonitorAlarm; +import com.ae2powertools.features.monitor.emitter.IEmitterCardHost; public class PowerToolsTheOneProbePlugin implements Function, IProbeInfoProvider { + private final PartAccessor partAccessor = new PartAccessor(); + public static void register() { FMLInterModComms.sendFunctionMessage( "theoneprobe", @@ -49,17 +60,43 @@ public void addProbeInfo(ProbeMode mode, World world, IBlockState blockState, IProbeHitData data) { - TileEntity tile = world.getTileEntity(data.getPos()); if (probeInfo == null) return; + TileEntity tile = world.getTileEntity(data.getPos()); + if (appendTileProbeInfo(probeInfo, player, tile)) return; + if (tile == null) return; + + Optional maybePart = this.partAccessor.getMaybePart(tile, data); + if (!maybePart.isPresent()) return; + + IPart part = maybePart.get(); + if (part instanceof IEmitterCardHost) { + addEmitterInfo(probeInfo, (IEmitterCardHost) part); + } + } + + private boolean appendTileProbeInfo(IProbeInfo probeInfo, EntityPlayer player, TileEntity tile) { if (tile instanceof TileAutoCrafter) { addAutoCrafterInfo(probeInfo, (TileAutoCrafter) tile); - return; + return true; } if (tile instanceof TileBetterLevelMaintainer) { addMaintainerInfo(probeInfo, (TileBetterLevelMaintainer) tile); + return true; } + + if (tile instanceof IEmitterCardHost) { + addEmitterInfo(probeInfo, (IEmitterCardHost) tile); + return true; + } + + if (tile instanceof TileLevelMonitorAlarm) { + addAlarmInfo(probeInfo, player, (TileLevelMonitorAlarm) tile); + return true; + } + + return false; } private void addAutoCrafterInfo(IProbeInfo probeInfo, TileAutoCrafter crafter) { @@ -93,8 +130,44 @@ private void addMaintainerInfo(IProbeInfo probeInfo, TileBetterLevelMaintainer m // Separation line probeInfo.text(""); + probeInfo.element(new TopTranslatedTextElement( + MaintainerProbeHelper.STATUS_CPU_TOOLTIP_KEY, + probeData.getCpuStatusArgs())); + + probeInfo.element(new TopTranslatedTextElement( + MaintainerProbeHelper.STATUS_RECIPE_TOOLTIP_KEY, + probeData.getRecipeStatusArgs())); + probeInfo.element(new TopTranslatedTextElement( probeData.getTimingKey(), probeData.getTimingArgs())); } + + private void addEmitterInfo(IProbeInfo probeInfo, IEmitterCardHost emitter) { + EmitterProbeData probeData = StorageMonitorProbeHelper.collectEmitterData(emitter); + if (!probeData.isValid()) return; + + // Separation line + probeInfo.text(""); + + if (probeData.hasFuzzyCard()) { + probeInfo.element(new TopTranslatedTextElement(StorageMonitorProbeHelper.EMITTER_FUZZY_CARD_TOOLTIP_KEY)); + } + + if (probeData.hasCraftingCard()) { + probeInfo.element(new TopTranslatedTextElement(StorageMonitorProbeHelper.EMITTER_CRAFTING_CARD_TOOLTIP_KEY)); + } + + probeInfo.element(new TopTranslatedTextElement(probeData.getRedstoneModeKey())); + } + + private void addAlarmInfo(IProbeInfo probeInfo, EntityPlayer player, TileLevelMonitorAlarm alarm) { + AlarmProbeData probeData = StorageMonitorProbeHelper.collectAlarmData(alarm, player); + if (!probeData.isValid()) return; + + // Separation line + probeInfo.text(""); + + probeInfo.element(new TopTranslatedTextElement(probeData.getRegistrationKey())); + } } \ No newline at end of file diff --git a/src/main/java/com/ae2powertools/integration/waila/PowerToolsWailaModule.java b/src/main/java/com/ae2powertools/integration/waila/PowerToolsWailaModule.java index c87e32e..67a5808 100644 --- a/src/main/java/com/ae2powertools/integration/waila/PowerToolsWailaModule.java +++ b/src/main/java/com/ae2powertools/integration/waila/PowerToolsWailaModule.java @@ -1,6 +1,7 @@ package com.ae2powertools.integration.waila; import java.util.List; +import java.util.Optional; import net.minecraft.client.resources.I18n; import net.minecraft.entity.player.EntityPlayerMP; @@ -8,10 +9,15 @@ import net.minecraft.nbt.NBTTagCompound; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.RayTraceResult; import net.minecraft.world.World; import net.minecraftforge.fml.common.event.FMLInterModComms; +import appeng.api.parts.IPart; import appeng.integration.modules.waila.BaseWailaDataProvider; +import appeng.integration.modules.waila.part.PartAccessor; +import appeng.integration.modules.waila.part.Tracer; +import appeng.tile.AEBaseTile; import mcp.mobius.waila.api.IWailaConfigHandler; import mcp.mobius.waila.api.IWailaDataAccessor; @@ -21,6 +27,11 @@ import com.ae2powertools.features.crafter.TileAutoCrafter; import com.ae2powertools.features.maintainer.MaintainerProbeHelper; import com.ae2powertools.features.maintainer.TileBetterLevelMaintainer; +import com.ae2powertools.features.monitor.StorageMonitorProbeHelper; +import com.ae2powertools.features.monitor.StorageMonitorProbeHelper.AlarmProbeData; +import com.ae2powertools.features.monitor.StorageMonitorProbeHelper.EmitterProbeData; +import com.ae2powertools.features.monitor.alarm.TileLevelMonitorAlarm; +import com.ae2powertools.features.monitor.emitter.IEmitterCardHost; public final class PowerToolsWailaModule { @@ -35,8 +46,18 @@ public static void register() { } public static void register(IWailaRegistrar registrar) { - registrar.registerBodyProvider(new AutoCrafterWailaDataProvider(), TileAutoCrafter.class); - registrar.registerBodyProvider(new MaintainerWailaDataProvider(), TileBetterLevelMaintainer.class); + AutoCrafterWailaDataProvider autoCrafterProvider = new AutoCrafterWailaDataProvider(); + MaintainerWailaDataProvider maintainerProvider = new MaintainerWailaDataProvider(); + StorageMonitorWailaDataProvider storageMonitorProvider = new StorageMonitorWailaDataProvider(); + + registrar.registerBodyProvider(autoCrafterProvider, TileAutoCrafter.class); + registrar.registerNBTProvider(autoCrafterProvider, TileAutoCrafter.class); + + registrar.registerBodyProvider(maintainerProvider, TileBetterLevelMaintainer.class); + registrar.registerNBTProvider(maintainerProvider, TileBetterLevelMaintainer.class); + + registrar.registerBodyProvider(storageMonitorProvider, AEBaseTile.class); + registrar.registerNBTProvider(storageMonitorProvider, AEBaseTile.class); } private static final class AutoCrafterWailaDataProvider extends BaseWailaDataProvider { @@ -102,6 +123,14 @@ public List getWailaBody(ItemStack itemStack, // Separation line currentToolTip.add(""); + currentToolTip.add(I18n.format( + MaintainerProbeHelper.STATUS_CPU_TOOLTIP_KEY, + (Object[]) probeData.getCpuStatusArgs())); + + currentToolTip.add(I18n.format( + MaintainerProbeHelper.STATUS_RECIPE_TOOLTIP_KEY, + (Object[]) probeData.getRecipeStatusArgs())); + currentToolTip.add(I18n.format( probeData.getTimingKey(), (Object[]) probeData.getTimingArgs())); @@ -122,4 +151,71 @@ public NBTTagCompound getNBTData(EntityPlayerMP player, return tag; } } + + private static final class StorageMonitorWailaDataProvider extends BaseWailaDataProvider { + + private final PartAccessor partAccessor = new PartAccessor(); + private final Tracer tracer = new Tracer(); + + @Override + public List getWailaBody(ItemStack itemStack, + List currentToolTip, + IWailaDataAccessor accessor, + IWailaConfigHandler config) { + NBTTagCompound tag = accessor.getNBTData(); + + EmitterProbeData emitterProbeData = StorageMonitorProbeHelper.readEmitterWailaData(tag); + if (emitterProbeData.isValid()) { + currentToolTip.add(""); + + if (emitterProbeData.hasFuzzyCard()) { + currentToolTip.add(I18n.format(StorageMonitorProbeHelper.EMITTER_FUZZY_CARD_TOOLTIP_KEY)); + } + + if (emitterProbeData.hasCraftingCard()) { + currentToolTip.add(I18n.format(StorageMonitorProbeHelper.EMITTER_CRAFTING_CARD_TOOLTIP_KEY)); + } + + currentToolTip.add(I18n.format(emitterProbeData.getRedstoneModeKey())); + return currentToolTip; + } + + AlarmProbeData alarmProbeData = StorageMonitorProbeHelper.readAlarmWailaData(tag); + if (!alarmProbeData.isValid()) return currentToolTip; + + currentToolTip.add(""); + currentToolTip.add(I18n.format(alarmProbeData.getRegistrationKey())); + return currentToolTip; + } + + @Override + public NBTTagCompound getNBTData(EntityPlayerMP player, + TileEntity te, + NBTTagCompound tag, + World world, + BlockPos pos) { + if (te instanceof IEmitterCardHost) { + StorageMonitorProbeHelper.writeEmitterWailaData((IEmitterCardHost) te, tag); + return tag; + } + + if (te instanceof TileLevelMonitorAlarm) { + StorageMonitorProbeHelper.writeAlarmWailaData((TileLevelMonitorAlarm) te, player, tag); + return tag; + } + + RayTraceResult hit = this.tracer.retraceBlock(world, player, pos); + if (hit == null) return tag; + + Optional maybePart = this.partAccessor.getMaybePart(te, hit); + if (!maybePart.isPresent()) return tag; + + IPart part = maybePart.get(); + if (part instanceof IEmitterCardHost) { + StorageMonitorProbeHelper.writeEmitterWailaData((IEmitterCardHost) part, tag); + } + + return tag; + } + } } \ No newline at end of file diff --git a/src/main/resources/assets/ae2powertools/lang/en_us.lang b/src/main/resources/assets/ae2powertools/lang/en_us.lang index 8b9345a..1e4adcc 100644 --- a/src/main/resources/assets/ae2powertools/lang/en_us.lang +++ b/src/main/resources/assets/ae2powertools/lang/en_us.lang @@ -357,6 +357,8 @@ ae2powertools.config.server.maintainer.maxCpuRetryCount.tooltip=Maximum number o # TOP/WAILA tooltip.ae2powertools.performance.none=Block work: no samples yet tooltip.ae2powertools.performance.summary=Block work: last %1$s / avg %2$s / max %3$s +tooltip.ae2powertools.maintainer.cpus=Crafting CPUs: §a%1$s§r / §8%2$s§r +tooltip.ae2powertools.maintainer.recipes=Recipes: §a%1$s§r / §8%2$s§r / §c%3$s§r / §5%4$s§r tooltip.ae2powertools.crafter.next_operation=Next operation in %s tooltip.ae2powertools.crafter.user_error.catalyst=§cError: missing catalyst(s)§r tooltip.ae2powertools.crafter.user_error.pattern=§cError: invalid pattern(s)§r @@ -369,6 +371,10 @@ tooltip.ae2powertools.crafter.patterns.active_full=Patterns: §a%1$s active§r / tooltip.ae2powertools.crafter.patterns.active_disabled=Patterns: §a%1$s active§r / §7%2$s disabled§r tooltip.ae2powertools.crafter.patterns.full_disabled=Patterns: §e%1$s full§r / §7%2$s disabled§r tooltip.ae2powertools.crafter.patterns.active_full_disabled=Patterns: §a%1$s active§r / §e%2$s full§r / §7%3$s disabled§r +tooltip.ae2powertools.storage_emitter.card.fuzzy=Card: §eFuzzy§r +tooltip.ae2powertools.storage_emitter.card.crafting=Card: §eCrafting§r +tooltip.ae2powertools.storage_emitter.redstone.weak=Redstone output: §bWeak§r +tooltip.ae2powertools.storage_emitter.redstone.strong=Redstone output: §dStrong§r # GUI - Main gui.ae2powertools.crafter.title=AutoCrafter From 6a74a769a2e35405172c7d7bc26ce9316b537120 Mon Sep 17 00:00:00 2001 From: ZHAY10086 Date: Tue, 4 Aug 2026 08:01:42 +0800 Subject: [PATCH 2/4] Update zh_cn.lang --- .../assets/ae2powertools/lang/zh_cn.lang | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/main/resources/assets/ae2powertools/lang/zh_cn.lang b/src/main/resources/assets/ae2powertools/lang/zh_cn.lang index 2969f3f..56aec9c 100644 --- a/src/main/resources/assets/ae2powertools/lang/zh_cn.lang +++ b/src/main/resources/assets/ae2powertools/lang/zh_cn.lang @@ -3,6 +3,11 @@ itemGroup.ae2powertools=AE2 PowerTools # Common strings ae2powertools.common.unknown=未知 +ae2powertools.common.upgrade.title=选择升级卡 +ae2powertools.common.upgrade.empty=点击选择一项升级卡。 +ae2powertools.common.upgrade.compatible=兼容: +ae2powertools.common.upgrade.action.select=左键点击选择另一升级卡 +ae2powertools.common.upgrade.action.remove=右键点击移除升级卡 # Config GUI and keys for the config factory ae2powertools.config.title=AE2 PowerTools设置 @@ -245,18 +250,18 @@ gui.ae2powertools.maintainer.error.extraction_failed=物品可见但无法提取 # ===================================================== # Items -item.ae2powertools.cards_distributor.name=卡片分配器 -item.ae2powertools.cards_distributor.tip1=对网络右击以从物品栏中分配卡片 -item.ae2powertools.cards_distributor.tip1bis=对网络右击以从物品栏和链接的AE2存储中分配卡片 +item.ae2powertools.cards_distributor.name=升级卡分配器 +item.ae2powertools.cards_distributor.tip1=对网络右击以从物品栏中分配升级卡 +item.ae2powertools.cards_distributor.tip1bis=对网络右击以从物品栏和链接的AE2存储中分配升级卡 item.ae2powertools.cards_distributor.tip2=支持分子装配室(加速卡) item.ae2powertools.cards_distributor.no_network=该位置未找到AE2网络。 item.ae2powertools.cards_distributor.use_on_network=对网络组件右击以分配加速卡。 # Messages item.ae2powertools.cards_distributor.success_accelerator=向%2$d个装配室分配了%1$d张加速卡。 -item.ae2powertools.cards_distributor.still_needed=还需%d张卡片才能完全升级%d个装配室。 +item.ae2powertools.cards_distributor.still_needed=还需%d张升级卡才能完全升级%d个装配室。 item.ae2powertools.cards_distributor.all_full=网络中的所有装配室都已完全升级! -item.ae2powertools.cards_distributor.pulled_from_ae2=从AE2网络存储中取出了%d张卡片。 +item.ae2powertools.cards_distributor.pulled_from_ae2=从AE2网络存储中取出了%d张升级卡。 # ===================================================== # Remote Storage Monitor @@ -352,6 +357,8 @@ ae2powertools.config.server.maintainer.maxCpuRetryCount.tooltip=任务在进入 # TOP/WAILA tooltip.ae2powertools.performance.none=方块工作:暂无样本 tooltip.ae2powertools.performance.summary=方块工作:最近 %1$s / 平均 %2$s / 最大 %3$s +tooltip.ae2powertools.maintainer.cpus=合成CPU:§a%1$s§r / §8%2$s§r +tooltip.ae2powertools.maintainer.recipes=配方:§a%1$s§r / §8%2$s§r / §c%3$s§r / §5%4$s§r tooltip.ae2powertools.crafter.next_operation=距下次操作还有 %s tooltip.ae2powertools.crafter.user_error.catalyst=§c错误:缺失催化剂§r tooltip.ae2powertools.crafter.user_error.pattern=§c错误:无效样板§r @@ -364,6 +371,10 @@ tooltip.ae2powertools.crafter.patterns.active_full=样板:§a%1$s 活跃§r / tooltip.ae2powertools.crafter.patterns.active_disabled=样板:§a%1$s 活跃§r / §7%2$s 已禁用§r tooltip.ae2powertools.crafter.patterns.full_disabled=样板:§e%1$s 已满§r / §7%2$s 已禁用§r tooltip.ae2powertools.crafter.patterns.active_full_disabled=样板:§a%1$s 活跃§r / §e%2$s 已满§r / §7%3$s 已禁用§r +tooltip.ae2powertools.storage_emitter.card.fuzzy=升级卡:§e模糊§r +tooltip.ae2powertools.storage_emitter.card.crafting=升级卡:§e合成§r +tooltip.ae2powertools.storage_emitter.redstone.weak=红石输出:§b弱信号§r +tooltip.ae2powertools.storage_emitter.redstone.strong=红石输出:§d强信号§r # GUI - Main gui.ae2powertools.crafter.title=自动合成器 @@ -533,6 +544,8 @@ gui.ae2powertools.storage_emitter.polling_rate.description=点击配置存储内 gui.ae2powertools.storage_emitter.strength=强度 gui.ae2powertools.storage_emitter.strength.tooltip=红石强度 gui.ae2powertools.storage_emitter.strength.description=红石强度指直接相邻方块接收到的初始强度。随后每传导一个红石粉,信号强度衰减1。 +gui.ae2powertools.storage_emitter.upgrade.fuzzy.description=将所有匹配的物品变种合并计数,而不只是精确匹配所选的物品堆叠。 +gui.ae2powertools.storage_emitter.upgrade.crafting.description=追踪当前正在合成的物品,而非网络中已存储的物品。 gui.ae2powertools.storage_emitter.empty_slot=未选择资源 gui.ae2powertools.storage_emitter.current_quantity=当前:%s gui.ae2powertools.storage_emitter.current_target=目标:%s %s (%s) From 64ed376116012e634221986d506183417c159c85 Mon Sep 17 00:00:00 2001 From: ZHAY10086 Date: Wed, 5 Aug 2026 15:39:23 +0800 Subject: [PATCH 3/4] Update zh_cn.lang --- .../resources/assets/ae2powertools/lang/zh_cn.lang | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/resources/assets/ae2powertools/lang/zh_cn.lang b/src/main/resources/assets/ae2powertools/lang/zh_cn.lang index 56aec9c..c8e7bcc 100644 --- a/src/main/resources/assets/ae2powertools/lang/zh_cn.lang +++ b/src/main/resources/assets/ae2powertools/lang/zh_cn.lang @@ -415,7 +415,7 @@ gui.ae2powertools.crafter.occupancy_desc=实际完成量占请求批量的百分 gui.ae2powertools.crafter.error_rate_desc=配方无法执行(错误状态)的操作占总尝试次数的比例 gui.ae2powertools.crafter.crafts_per_operation=每%2$s合成%1$s gui.ae2powertools.crafter.issues=问题 -gui.ae2powertools.crafter.crafts_per_operation=%s 物品 / %s +gui.ae2powertools.crafter.crafts_per_operation=§2%s§8 物品 / %s # GUI - Errors gui.ae2powertools.crafter.error.not_pattern=物品不是合成样板 @@ -425,12 +425,12 @@ gui.ae2powertools.crafter.error.processing_pattern=仅支持合成样板,不 # GUI - Warnings (tooltips) gui.ae2powertools.crafter.warning.processing_pattern_title=警告:处理样板! gui.ae2powertools.crafter.warning.processing_pattern_desc=自动合成器仅接受合成样板。 -gui.ae2powertools.crafter.error.need_have=%s(需要%d,现有%d) -gui.ae2powertools.crafter.error.limited_by=受限于%s(分配%d,需要%d) +gui.ae2powertools.crafter.error.need_have=§b%s§7(需要§r%d§7,现有§r%d§7) +gui.ae2powertools.crafter.error.limited_by=受限于§b%s§7(分配§r%d§7,需要§r%d§7) gui.ae2powertools.crafter.error.no_items_in_network=网络中无可用物品 -gui.ae2powertools.crafter.error.missing_catalyst_slot=槽位%d缺失催化剂:%s -gui.ae2powertools.crafter.error.wrong_catalyst_slot=槽位%d物品错误:应当是%s,实际为%s -gui.ae2powertools.crafter.error.pending_output=无法将%d x %s插入网络 +gui.ae2powertools.crafter.error.missing_catalyst_slot=槽位%d缺失催化剂§7:§b%s +gui.ae2powertools.crafter.error.wrong_catalyst_slot=槽位%d物品错误§7:应当是§b%s§7,实际为%s +gui.ae2powertools.crafter.error.pending_output=无法将%d§7 x %s§7插入网络 gui.ae2powertools.crafter.error.inputs_changed=所需输入原料在提取前从网络中消失了(你的网络中可能存在幽灵物品) gui.ae2powertools.crafter.error.catalyst_recipe_mismatch=当前催化剂物品与编码样板不再匹配 gui.ae2powertools.crafter.error.output_mismatch=当前催化剂物品导致的产物与编码样板不同 From 680d88d4c096a6363773b0748e1341ca7225da91 Mon Sep 17 00:00:00 2001 From: ZHAY10086 Date: Wed, 12 Aug 2026 11:50:49 +0800 Subject: [PATCH 4/4] Update zh_cn.lang --- .../resources/assets/ae2powertools/lang/zh_cn.lang | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/resources/assets/ae2powertools/lang/zh_cn.lang b/src/main/resources/assets/ae2powertools/lang/zh_cn.lang index c8e7bcc..a3dc3b6 100644 --- a/src/main/resources/assets/ae2powertools/lang/zh_cn.lang +++ b/src/main/resources/assets/ae2powertools/lang/zh_cn.lang @@ -284,6 +284,8 @@ gui.ae2powertools.remote_monitor.polling_rate.description=设置用于衡量数 gui.ae2powertools.remote_monitor.refresh_interval.title=刷新间隔 gui.ae2powertools.remote_monitor.refresh_interval.tooltip=每隔%s刷新一次采样数量 gui.ae2powertools.remote_monitor.refresh_interval.description=设置远程监控器轮询网络的频率 +gui.ae2powertools.poll_now.title=立即刷新 +gui.ae2powertools.poll_now.description=立即触发一次该监控器的网络轮询 gui.ae2powertools.remote_monitor.sliding_window.title=滑动窗口 gui.ae2powertools.remote_monitor.sliding_window.tooltip=与最近%s进行对比 gui.ae2powertools.remote_monitor.sliding_window.description=设置用于衡量数量变化的时间跨度 @@ -333,10 +335,10 @@ tile.ae2powertools.auto_crafter.memory_card.no_blanks= - 物品栏中缺少%d个 tile.ae2powertools.auto_crafter.memory_card.no_slots= - 自动合成器中缺少%d个空闲槽位。 # Items - Speed Upgrades -item.ae2powertools.crafter_speed_upgrade_i.name=速度升级 I -item.ae2powertools.crafter_speed_upgrade_ii.name=速度升级 II -item.ae2powertools.crafter_speed_upgrade_iii.name=速度升级 III -item.ae2powertools.crafter_speed_upgrade_iv.name=速度升级 IV +item.ae2powertools.crafter_speed_upgrade_i.name=速度升级卡 I +item.ae2powertools.crafter_speed_upgrade_ii.name=速度升级卡 II +item.ae2powertools.crafter_speed_upgrade_iii.name=速度升级卡 III +item.ae2powertools.crafter_speed_upgrade_iv.name=速度升级卡 IV item.ae2powertools.crafter_speed_upgrade.tooltip=批量大小x%d。放入自动合成器以增加吞吐量。 # Config